use crate::context::Context; use crate::schemas::path; use crate::step::BoolCollector; use crate::step::Node; use crate::step::StepMaker; use crate::CompilationError; use preserves::value::IOValue; pub trait Predicate: std::fmt::Debug { fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool; } #[derive(Debug)] pub enum CompiledPredicate { Selector(Node), Not(Box), Or(Vec), And(Vec), } impl path::Predicate { pub fn compile(&self) -> Result { match self { path::Predicate::Selector(b) => Ok(CompiledPredicate::Selector( (&**b).connect(BoolCollector::new())?, )), path::Predicate::Not { pred } => { Ok(CompiledPredicate::Not(Box::new((&**pred).compile()?))) } path::Predicate::Or { preds } => Ok(CompiledPredicate::Or( preds.iter().map(Self::compile).collect::>()?, )), path::Predicate::And { preds } => Ok(CompiledPredicate::And( preds.iter().map(Self::compile).collect::>()?, )), } } pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Result { Ok(self.compile()?.test(ctxt, value)) } } impl Predicate for CompiledPredicate { fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool { match self { CompiledPredicate::Selector(n) => n.test(ctxt, value), CompiledPredicate::Not(p) => !p.test(ctxt, value), CompiledPredicate::Or(ps) => { for p in ps.iter_mut() { if p.test(ctxt, value) { return true; } } return false; } CompiledPredicate::And(ps) => { for p in ps.iter_mut() { if !p.test(ctxt, value) { return false; } } return true; } } } }