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}