1use crate::regexp::RegExp;
2use crate::Error;
3
4#[derive(Debug)]
5pub(crate) struct Matcher<R: RegExp> {
8  pub prefix: String,
9  pub suffix: String,
10  pub inner: InnerMatcher<R>,
11  pub ignore_case: bool,
12}
13
14#[derive(Debug)]
15pub(crate) enum InnerMatcher<R: RegExp> {
16  Literal { literal: String },
22  SingleCapture {
33    filter: Option<char>,
34    allow_empty: bool,
35  },
36  RegExp { regexp: Result<R, Error> },
42}
43
44impl<R: RegExp> Matcher<R> {
45  pub fn matches<'a>(
46    &self,
47    mut input: &'a str,
48  ) -> Option<Vec<Option<&'a str>>> {
49    let prefix_len = self.prefix.len();
50    let suffix_len = self.suffix.len();
51    let input_len = input.len();
52    if prefix_len + suffix_len > 0 {
53      if input_len < prefix_len + suffix_len {
56        return None;
57      }
58      if !input.starts_with(&self.prefix) {
59        return None;
60      }
61      if !input.ends_with(&self.suffix) {
62        return None;
63      }
64      input = &input[prefix_len..input_len - suffix_len];
65    }
66
67    match &self.inner {
68      InnerMatcher::Literal { literal } => {
69        if self.ignore_case {
70          (input.to_lowercase() == literal.to_lowercase()).then(Vec::new)
71        } else {
72          (input == literal).then(Vec::new)
73        }
74      }
75      InnerMatcher::SingleCapture {
76        filter,
77        allow_empty,
78      } => {
79        if input.is_empty() && !allow_empty {
80          return None;
81        }
82        if let Some(filter) = filter {
83          if self.ignore_case {
84            if input
85              .to_lowercase()
86              .contains(filter.to_lowercase().collect::<Vec<_>>().as_slice())
87            {
88              return None;
89            }
90          } else if input.contains(*filter) {
91            return None;
92          }
93        }
94        Some(vec![Some(input)])
95      }
96      InnerMatcher::RegExp { regexp, .. } => {
97        regexp.as_ref().unwrap().matches(input)
98      }
99    }
100  }
101}