humblegen_rt/
regexset_map.rs1use core::fmt;
11
12pub struct RegexSetMap<I, T: Entry<I>> {
14 set: regex::RegexSet,
15 entries: Vec<T>,
16 _marker: std::marker::PhantomData<I>,
17}
18
19pub trait Entry<I> {
21 fn regex(&self) -> ®ex::Regex;
22 fn matches_input(&self, i: &I) -> bool;
23}
24
25impl<I, T: Entry<I>> Entry<I> for (regex::Regex, T) {
26 fn regex(&self) -> ®ex::Regex {
27 &self.0
28 }
29 fn matches_input(&self, i: &I) -> bool {
30 self.1.matches_input(i)
31 }
32}
33
34impl<I, T: Entry<I>> fmt::Debug for RegexSetMap<I, T> {
35 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
36 formatter
37 .debug_struct("RegexSetMap")
38 .field("set.patterns", &self.set.patterns())
39 .field("entries", &"<NoTraitSpecialization>")
40 .finish()
41 }
42}
43
44#[derive(Debug)]
46pub enum GetResult<'a, T> {
47 None,
48 One(&'a T),
49 Ambiguous,
50}
51
52impl<I, T: Entry<I>> RegexSetMap<I, T> {
53 pub fn new(entries: Vec<T>) -> Result<Self, regex::Error> {
55 let set = regex::RegexSet::new(entries.iter().map(|r| r.regex().as_str())).unwrap();
56 Ok(Self {
57 set,
58 entries,
59 _marker: std::marker::PhantomData::default(),
60 })
61 }
62
63 pub fn get(&self, s: &str, input: &I) -> GetResult<'_, T> {
65 let mut matching_route_idxs = self
66 .set
67 .matches(s)
68 .into_iter()
69 .filter(|matching_idx| self.entries[*matching_idx].matches_input(input))
70 .peekable();
71
72 let matching_route_idx = matching_route_idxs.next();
73 let next_matching_route_idx = matching_route_idxs.peek();
74
75 let matching_idx = match (matching_route_idx, next_matching_route_idx) {
76 (Some(idx), None) => idx,
77 (None, s @ Some(_)) => {
78 unreachable!("peek after next() == None always returns None, got {:?}", s)
79 }
80 (None, None) => {
81 return GetResult::None;
82 }
83 (Some(_), Some(_)) => {
84 return GetResult::Ambiguous;
85 }
86 };
87
88 GetResult::One(&self.entries[matching_idx])
89 }
90}