use crate::regexp::RegExp;
use crate::Error;
#[derive(Debug)]
pub(crate) struct Matcher<R: RegExp> {
pub prefix: String,
pub suffix: String,
pub inner: InnerMatcher<R>,
pub ignore_case: bool,
}
#[derive(Debug)]
pub(crate) enum InnerMatcher<R: RegExp> {
Literal { literal: String },
SingleCapture {
filter: Option<char>,
allow_empty: bool,
},
RegExp { regexp: Result<R, Error> },
}
impl<R: RegExp> Matcher<R> {
pub fn matches<'a>(
&self,
mut input: &'a str,
) -> Option<Vec<Option<&'a str>>> {
let prefix_len = self.prefix.len();
let suffix_len = self.suffix.len();
let input_len = input.len();
if prefix_len + suffix_len > 0 {
if input_len < prefix_len + suffix_len {
return None;
}
if !input.starts_with(&self.prefix) {
return None;
}
if !input.ends_with(&self.suffix) {
return None;
}
input = &input[prefix_len..input_len - suffix_len];
}
match &self.inner {
InnerMatcher::Literal { literal } => {
if self.ignore_case {
(input.to_lowercase() == literal.to_lowercase()).then(Vec::new)
} else {
(input == literal).then(Vec::new)
}
}
InnerMatcher::SingleCapture {
filter,
allow_empty,
} => {
if input.is_empty() && !allow_empty {
return None;
}
if let Some(filter) = filter {
if self.ignore_case {
if input
.to_lowercase()
.contains(filter.to_lowercase().collect::<Vec<_>>().as_slice())
{
return None;
}
} else if input.contains(*filter) {
return None;
}
}
Some(vec![Some(input)])
}
InnerMatcher::RegExp { regexp, .. } => {
regexp.as_ref().unwrap().matches(input)
}
}
}
}