use std::fmt;
use std::iter;
use std::slice;
use std::vec;
use exec::{Exec, ExecBuilder, Search};
use Error;
macro_rules! define_set {
(
$ty:ident,
$ty_set_matches:ident,
$ty_set_matches_iter:ident,
$ty_set_matches_into_iter:ident,
$exec_build:expr,
$text_ty:ty,
$as_bytes:expr
) => {
#[derive(Clone)]
pub struct $ty(Exec);
impl $ty {
pub fn new<I, S>(exprs: I) -> Result<$ty, Error>
where S: AsRef<str>, I: IntoIterator<Item=S> {
let exec = try!($exec_build(exprs));
if exec.regex_strings().len() < 2 {
return Err(Error::InvalidSet);
}
Ok($ty(exec))
}
pub fn is_match(&self, text: $text_ty) -> bool {
let mut search = Search::new(&mut [], &mut []);
self.0.exec(&mut search, $as_bytes(text), 0)
}
pub fn matches(&self, text: $text_ty) -> SetMatches {
let mut matches = vec![false; self.0.matches().len()];
let matched_any = {
let mut search = Search::new(&mut [], &mut matches);
self.0.exec(&mut search, $as_bytes(text), 0)
};
SetMatches {
matched_any: matched_any,
matches: matches,
}
}
pub fn len(&self) -> usize {
self.0.regex_strings().len()
}
}
#[derive(Clone, Debug)]
pub struct $ty_set_matches {
matched_any: bool,
matches: Vec<bool>,
}
impl $ty_set_matches {
pub fn matched_any(&self) -> bool {
self.matched_any
}
pub fn matched(&self, regex_index: usize) -> bool {
self.matches[regex_index]
}
pub fn len(&self) -> usize {
self.matches.len()
}
pub fn iter(&self) -> $ty_set_matches_iter {
$ty_set_matches_iter((&*self.matches).into_iter().enumerate())
}
}
impl IntoIterator for $ty_set_matches {
type IntoIter = $ty_set_matches_into_iter;
type Item = usize;
fn into_iter(self) -> Self::IntoIter {
$ty_set_matches_into_iter(self.matches.into_iter().enumerate())
}
}
impl<'a> IntoIterator for &'a $ty_set_matches {
type IntoIter = $ty_set_matches_iter<'a>;
type Item = usize;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct $ty_set_matches_into_iter(iter::Enumerate<vec::IntoIter<bool>>);
impl Iterator for $ty_set_matches_into_iter {
type Item = usize;
fn next(&mut self) -> Option<usize> {
loop {
match self.0.next() {
None => return None,
Some((_, false)) => {}
Some((i, true)) => return Some(i),
}
}
}
}
#[derive(Clone)]
pub struct $ty_set_matches_iter<'a>(iter::Enumerate<slice::Iter<'a, bool>>);
impl<'a> Iterator for $ty_set_matches_iter<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
loop {
match self.0.next() {
None => return None,
Some((_, &false)) => {}
Some((i, &true)) => return Some(i),
}
}
}
}
}
}
fn as_bytes_str(text: &str) -> &[u8] { text.as_bytes() }
fn as_bytes_bytes(text: &[u8]) -> &[u8] { text }
define_set! {
RegexSet,
SetMatches,
SetMatchesIter,
SetMatchesIntoIter,
|exprs| ExecBuilder::new_many(exprs).build(),
&str,
as_bytes_str
}
define_set! {
RegexSetBytes,
SetMatchesBytes,
SetMatchesIterBytes,
SetMatchesIntoIterBytes,
|exprs| ExecBuilder::new_many(exprs).only_utf8(false).build(),
&[u8],
as_bytes_bytes
}
impl fmt::Debug for RegexSet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RegexSet({:?})", self.0.regex_strings())
}
}
impl fmt::Debug for RegexSetBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RegexSet({:?})", self.0.regex_strings())
}
}