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    async fn get_fn(&self, name: &str) -> Result<Option<&BoxedExprFn>, Error> {
45        Err(Error::NoSuchFunction(name.to_string()))
46    }
47}
48
49/// A simple context that stores the variables in a hash map.
50/// 
51/// For those who don't want to implement the `Context` trait, this is a simple
52/// implementation that can be used.
53pub struct SimpleContext {
54    vars: HashMap<String, ExprValue>,
55    fns: HashMap<String, BoxedExprFn>,
56}
57
58impl SimpleContext {
59    pub fn new(vars: HashMap<String, ExprValue>) -> Self {
60        Self {
61            vars,
62            fns: HashMap::new(),
63        }
64    }
65
66    pub fn add_fn(&mut self, name: String, func: BoxedExprFn) {
67        self.fns.insert(name, func);
68    }
69}
70
71#[async_trait::async_trait]
72impl Context for SimpleContext {
73    async fn get_var(&self, name: &str) -> Result<ExprValue, Error> {
74        self.vars
75            .get(name)
76            .cloned()
77            .ok_or(Error::NoSuchVar(name.to_string()))
78    }
79
80    async fn get_fn(&self, name: &str) -> Result<Option<&BoxedExprFn>, Error> {
81        Ok(self.fns.get(name))
82    }
83}