use super::field_predicate::FieldPredicate;
use std::ops::{BitAnd, BitOr, BitXor, Not};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum BasicPredicate<T> {
True,
False,
Field(FieldPredicate<T>),
And(Vec<BasicPredicate<T>>),
Or(Vec<BasicPredicate<T>>),
Not(Box<BasicPredicate<T>>),
Xor(Box<BasicPredicate<T>>, Box<BasicPredicate<T>>),
}
impl<T> BasicPredicate<T> {
pub fn evaluate(&self, value: &T) -> bool {
match self {
Self::True => true,
Self::False => false,
Self::Field(fp) => fp.evaluate(value),
Self::And(children) => children.iter().all(|c| c.evaluate(value)),
Self::Or(children) => children.iter().any(|c| c.evaluate(value)),
Self::Not(inner) => !inner.evaluate(value),
Self::Xor(a, b) => a.evaluate(value) ^ b.evaluate(value),
}
}
}
impl<T> BitAnd for BasicPredicate<T> {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::And(mut l), Self::And(r)) => {
l.extend(r);
Self::And(l)
}
(Self::And(mut l), r) => {
l.push(r);
Self::And(l)
}
(l, Self::And(mut r)) => {
r.insert(0, l);
Self::And(r)
}
(l, r) => Self::And(vec![l, r]),
}
}
}
impl<T> BitOr for BasicPredicate<T> {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::Or(mut l), Self::Or(r)) => {
l.extend(r);
Self::Or(l)
}
(Self::Or(mut l), r) => {
l.push(r);
Self::Or(l)
}
(l, Self::Or(mut r)) => {
r.insert(0, l);
Self::Or(r)
}
(l, r) => Self::Or(vec![l, r]),
}
}
}
impl<T> BitXor for BasicPredicate<T> {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self {
Self::Xor(Box::new(self), Box::new(rhs))
}
}
impl<T> Not for BasicPredicate<T> {
type Output = Self;
fn not(self) -> Self {
match self {
Self::Not(inner) => *inner, Self::True => Self::False,
Self::False => Self::True,
other => Self::Not(Box::new(other)),
}
}
}