#[cfg(feature = "serde")] use serde::Serialize;
#[cfg(feature = "serde")] use serde::Deserialize;
pub trait Eval: Clone + PartialEq {
type Context;
fn eval(&self, data: &Self::Context) -> bool;
}
#[derive(Debug, Clone, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Expr<V> {
Var(V),
Not(Box<Expr<V>>),
Or(Box<Expr<V>>, Box<Expr<V>>),
And(Box<Expr<V>>, Box<Expr<V>>),
}
impl<V> Expr<V> {
pub fn map<F, X>(self, f: F) -> Expr<X>
where F: Fn(V) -> X
{
self.map_inner(&f)
}
fn map_inner<F, X>(self, f: &F) -> Expr<X>
where F: Fn(V) -> X
{
use Expr::*;
match self {
Var(v) => Var(f(v)),
Not(p) => Not(Box::new(p.map_inner(f))),
And(a, b) => And(
Box::new(a.map_inner(f)),
Box::new(b.map_inner(f))),
Or(a, b) => Or(
Box::new(a.map_inner(f)),
Box::new(b.map_inner(f))),
}
}
pub (in crate) fn pushdown_not(self) -> Self {
use Expr::*;
if let Not(expr) = self {
match *expr {
Var(p) => Not(Box::new(Var(p))),
Not(p) => p.pushdown_not(),
Or(a, b) => And(Box::new(Not(a)), Box::new(Not(b))),
And(a, b) => Or(Box::new(Not(a)), Box::new(Not(b))),
}
} else {
self
}
}
}
impl<V> Expr<V> where V: PartialEq {
pub fn eq_repr(&self, other: &Self) -> bool {
use Expr::*;
match (self, other) {
(Var(a), Var(b)) => a == b,
(Not(a), Not(b)) => a.eq_repr(b),
(Or(a1, b1), Or(a2, b2)) => {
a1.eq_repr(b1) &&
a2.eq_repr(b2)
},
(And(a1, b1), And(a2, b2)) => {
a1.eq_repr(b1) &&
a2.eq_repr(b2)
},
_ => false,
}
}
pub (in crate) fn simplify(self) -> Self {
use Expr::*;
match self {
Not(p) => match *p {
Not(q) => q.simplify(),
q => Not(Box::new(q.simplify())),
}
And(a, b) => {
let a = a.simplify();
let b = b.simplify();
if a == b { a } else { And(Box::new(a), Box::new(b)) }
},
Or(a, b) => {
let a = a.simplify();
let b = b.simplify();
if a == b { a } else { Or(Box::new(a), Box::new(b)) }
},
_ => self,
}
}
}
impl<V> Expr<V> where V: Clone {
pub (in crate) fn distribute_and(self) -> Self {
use Expr::*;
if let And(a, b) = self {
match (*a, *b) {
(p, Or(q, r)) |
(Or(q, r), p) => Or(
Box::new(And(Box::new(p.clone()), q)),
Box::new(And(Box::new(p), r))),
(a, b) => And(Box::new(a), Box::new(b))
}
} else {
self
}
}
pub (in crate) fn distribute_or(self) -> Self {
use Expr::*;
if let Or(a, b) = self {
match (*a, *b) {
(p, And(q, r)) |
(And(q, r), p) => And(
Box::new(Or(Box::new(p.clone()), q)),
Box::new(Or(Box::new(p), r))),
(a, b) => Or(Box::new(a), Box::new(b))
}
} else {
self
}
}
}
impl<V> Eval for Expr<V> where V: Eval {
type Context = V::Context;
fn eval(&self, data: &Self::Context) -> bool {
use Expr::*;
match self {
Var(p) => p.eval(data),
Not(p) => !p.eval(data),
Or(a, b) => a.eval(data) || b.eval(data),
And(a, b) => a.eval(data) && b.eval(data),
}
}
}
impl<V> PartialEq for Expr<V> where V: PartialEq {
fn eq(&self, other: &Self) -> bool {
use Expr::*;
match (self, other) {
(Var(p1), Var(p2)) => p1 == p2,
(Not(p1), Not(p2)) => p1 == p2,
(Or(a1, b1), Or(a2, b2)) =>
(a1 == a2 && b1 == b2) || (a1 == b2 && b1 == a2),
(And(a1, b1), And(a2, b2)) =>
(a1 == a2 && b1 == b2) || (a1 == b2 && b1 == a2),
_ => false,
}
}
}