harper_core/patterns/
pattern_map.rs

1use crate::LSend;
2use crate::Token;
3
4use super::Pattern;
5
6/// A map from [`Pattern`] to arbitrary data.
7///
8/// When used as a [`Pattern`] in of itself, it simply iterates through
9/// all contained patterns, returning the first match found.
10/// You should not assume this search is deterministic.
11///
12/// If you'd like to use this structure in a [`PatternLinter`](crate::linting::PatternLinter), you may want to provide
13/// the map as the search pattern, then use a pattern look-up once more to determine
14/// the corresponding key.
15pub struct PatternMap<T>
16where
17    T: LSend,
18{
19    rows: Vec<Row<T>>,
20}
21
22struct Row<T>
23where
24    T: LSend,
25{
26    pub key: Box<dyn Pattern>,
27    pub element: T,
28}
29
30impl<T> Default for PatternMap<T>
31where
32    T: LSend,
33{
34    fn default() -> Self {
35        Self {
36            rows: Default::default(),
37        }
38    }
39}
40
41impl<T> PatternMap<T>
42where
43    T: LSend,
44{
45    pub fn insert(&mut self, pattern: impl Pattern + 'static, value: T) {
46        self.rows.push(Row {
47            key: Box::new(pattern),
48            element: value,
49        });
50    }
51
52    /// Lookup the corresponding value for the given map.
53    pub fn lookup(&self, tokens: &[Token], source: &[char]) -> Option<&T> {
54        for row in &self.rows {
55            let len = row.key.matches(tokens, source);
56
57            if len != 0 {
58                return Some(&row.element);
59            }
60        }
61
62        None
63    }
64}
65
66impl<T> Pattern for PatternMap<T>
67where
68    T: LSend,
69{
70    fn matches(&self, tokens: &[Token], source: &[char]) -> usize {
71        for row in &self.rows {
72            let len = row.key.matches(tokens, source);
73
74            if len != 0 {
75                return len;
76            }
77        }
78
79        0
80    }
81}