harper_core/expr/
expr_map.rs

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