filter_expr_evaler/
ctx.rs

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