preserves/implementations/rust/preserves-path/src/predicate.rs

68 lines
2.1 KiB
Rust

use crate::CompilationError;
use crate::path::Path;
use crate::schemas::path;
use crate::step::BoolCollector;
use crate::step::Node;
use crate::step::StepMaker;
use preserves::value::IOValue;
use std::rc::Rc;
pub trait Predicate: std::fmt::Debug {
fn test(&mut self, path: Rc<Path>, value: &IOValue) -> bool;
}
#[derive(Debug)]
pub enum CompiledPredicate {
Selector(Node),
Not(Box<CompiledPredicate>),
Or(Vec<CompiledPredicate>),
And(Vec<CompiledPredicate>),
}
impl path::Predicate {
pub fn compile(&self) -> Result<CompiledPredicate, CompilationError> {
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::<Result<_,_>>()?)),
path::Predicate::And { preds } =>
Ok(CompiledPredicate::And(preds.iter().map(Self::compile).collect::<Result<_,_>>()?)),
}
}
pub fn exec(&self, value: &IOValue) -> Result<bool, CompilationError> {
Ok(self.compile()?.test(Path::root(), value))
}
}
impl Predicate for CompiledPredicate {
fn test(&mut self, path: Rc<Path>, value: &IOValue) -> bool {
match self {
CompiledPredicate::Selector(n) => n.test(path, value),
CompiledPredicate::Not(p) => !p.test(path, value),
CompiledPredicate::Or(ps) => {
for p in ps.iter_mut() {
if p.test(Rc::clone(&path), value) {
return true;
}
}
return false;
},
CompiledPredicate::And(ps) => {
for p in ps.iter_mut() {
if !p.test(Rc::clone(&path), value) {
return false;
}
}
return true;
},
}
}
}