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