filter_expr/
ctx.rs

1use std::collections::HashMap;
2
3use crate::{Error, expr::{BoxedExprFn, ExprValue}};
4
5/// A macro to create a `SimpleContext` from key-value pairs.
6///
7/// # Example
8///
9/// ```rust
10/// use filter_expr::simple_context;
11///
12/// let ctx = simple_context! {
13///     "name": "John",
14///     "age": 19,
15/// };
16/// ```
17#[macro_export]
18macro_rules! simple_context {
19    // Empty case.
20    () => {
21        $crate::SimpleContext::new(std::collections::HashMap::new())
22    };
23    
24    // Single key-value pair.
25    ($key:literal : $value:expr $(,)?) => {
26        $crate::SimpleContext::new(std::collections::HashMap::from([
27            ($key.to_string(), ($value).into()),
28        ]))
29    };
30    
31    // Multiple key-value pairs.
32    ($key:literal : $value:expr, $($rest_key:literal : $rest_value:expr),* $(,)?) => {
33        $crate::SimpleContext::new(std::collections::HashMap::from([
34            ($key.to_string(), ($value).into()),
35            $(($rest_key.to_string(), ($rest_value).into())),*
36        ]))
37    };
38}
39
40/// The context of the filter for evaluation.
41#[async_trait::async_trait]
42pub trait Context: Send + Sync {
43    async fn get_var(&self, name: &str) -> Result<ExprValue, Error>;
44
45    async fn get_fn(&self, name: &str) -> Option<&BoxedExprFn> {
46        let _name = name;
47
48        None
49    }
50}
51
52/// A simple context that stores the variables in a hash map.
53/// 
54/// For those who don't want to implement the `Context` trait, this is a simple
55/// implementation that can be used.
56pub struct SimpleContext {
57    vars: HashMap<String, ExprValue>,
58    fns: HashMap<String, BoxedExprFn>,
59}
60
61impl SimpleContext {
62    pub fn new(vars: HashMap<String, ExprValue>) -> Self {
63        Self {
64            vars,
65            fns: HashMap::new(),
66        }
67    }
68
69    pub fn add_fn(&mut self, name: String, func: BoxedExprFn) {
70        self.fns.insert(name, func);
71    }
72}
73
74#[async_trait::async_trait]
75impl Context for SimpleContext {
76    async fn get_var(&self, name: &str) -> Result<ExprValue, Error> {
77        self.vars
78            .get(name)
79            .cloned()
80            .ok_or(Error::NoSuchVar(name.to_string()))
81    }
82
83    async fn get_fn(&self, name: &str) -> Option<&BoxedExprFn> {
84        self.fns.get(name)
85    }
86}