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