use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
String(String),
Int(i64),
Float(f64),
Bool(bool),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CmpOp {
Eq,
Neq,
Lt,
Le,
Gt,
Ge,
Like,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
Not(Box<Expr>),
Cmp {
lhs: Operand,
op: CmpOp,
rhs: Operand,
},
Between {
field: Operand,
low: Operand,
high: Operand,
negated: bool,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum Operand {
Literal(Value),
Field(String),
Param(u32),
}
impl Expr {
#[must_use]
pub fn node_count(&self) -> usize {
match self {
Self::And(a, b) | Self::Or(a, b) => 1 + a.node_count() + b.node_count(),
Self::Not(inner) => 1 + inner.node_count(),
Self::Cmp { .. } => 1,
Self::Between { .. } => 1,
}
}
#[must_use]
pub fn collect_param_indices(&self) -> Vec<u32> {
fn walk(e: &Expr, out: &mut Vec<u32>) {
match e {
Expr::And(a, b) | Expr::Or(a, b) => {
walk(a, out);
walk(b, out);
}
Expr::Not(inner) => walk(inner, out),
Expr::Cmp { lhs, rhs, .. } => {
if let Operand::Param(i) = lhs {
out.push(*i);
}
if let Operand::Param(i) = rhs {
out.push(*i);
}
}
Expr::Between {
field, low, high, ..
} => {
for op in [field, low, high] {
if let Operand::Param(i) = op {
out.push(*i);
}
}
}
}
}
let mut out = Vec::new();
walk(self, &mut out);
out
}
}