1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
7#[serde(tag = "op", rename_all = "snake_case")]
8pub enum Expr {
9 LiteralBool { value: bool },
10 Eq { left: String, right: String },
11 And { expressions: Vec<Expr> },
12 Or { expressions: Vec<Expr> },
13 Not { expression: Box<Expr> },
14 Var { path: String },
15}
16
17impl Expr {
18 fn get_value<'a>(ctx: &'a Value, path: &str) -> Option<&'a Value> {
19 ctx.pointer(path)
20 }
21
22 pub fn evaluate(&self, ctx: &Value) -> Option<bool> {
24 match self {
25 Expr::LiteralBool { value } => Some(*value),
26 Expr::Eq { left, right } => {
27 let left_val = Self::get_value(ctx, left)?;
28 let right_val = Self::get_value(ctx, right)?;
29 Some(left_val == right_val)
30 }
31 Expr::And { expressions } => {
32 for expr in expressions {
33 match expr.evaluate(ctx) {
34 Some(true) => continue,
35 Some(false) => return Some(false),
36 None => return None,
37 }
38 }
39 Some(true)
40 }
41 Expr::Or { expressions } => {
42 for expr in expressions {
43 if let Some(true) = expr.evaluate(ctx) {
44 return Some(true);
45 }
46 }
47 Some(false)
48 }
49 Expr::Not { expression } => expression.evaluate(ctx).map(|value| !value),
50 Expr::Var { path } => Self::get_value(ctx, path).and_then(|v| v.as_bool()),
51 }
52 }
53}