preserves_path/
predicate.rs

1use crate::context::Context;
2use crate::schemas::path;
3use crate::step::BoolCollector;
4use crate::step::Node;
5use crate::step::StepMaker;
6use crate::CompilationError;
7
8use preserves::value::IOValue;
9
10pub trait Predicate: std::fmt::Debug {
11    fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool;
12}
13
14#[derive(Debug)]
15pub enum CompiledPredicate {
16    Selector(Node),
17    Not(Box<CompiledPredicate>),
18    Or(Vec<CompiledPredicate>),
19    And(Vec<CompiledPredicate>),
20}
21
22impl path::Predicate {
23    pub fn compile(&self) -> Result<CompiledPredicate, CompilationError> {
24        match self {
25            path::Predicate::Selector(b) => Ok(CompiledPredicate::Selector(
26                (&**b).connect(BoolCollector::new())?,
27            )),
28            path::Predicate::Not { pred } => {
29                Ok(CompiledPredicate::Not(Box::new((&**pred).compile()?)))
30            }
31            path::Predicate::Or { preds } => Ok(CompiledPredicate::Or(
32                preds.iter().map(Self::compile).collect::<Result<_, _>>()?,
33            )),
34            path::Predicate::And { preds } => Ok(CompiledPredicate::And(
35                preds.iter().map(Self::compile).collect::<Result<_, _>>()?,
36            )),
37        }
38    }
39
40    pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Result<bool, CompilationError> {
41        Ok(self.compile()?.test(ctxt, value))
42    }
43}
44
45impl Predicate for CompiledPredicate {
46    fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool {
47        match self {
48            CompiledPredicate::Selector(n) => n.test(ctxt, value),
49            CompiledPredicate::Not(p) => !p.test(ctxt, value),
50            CompiledPredicate::Or(ps) => {
51                for p in ps.iter_mut() {
52                    if p.test(ctxt, value) {
53                        return true;
54                    }
55                }
56                return false;
57            }
58            CompiledPredicate::And(ps) => {
59                for p in ps.iter_mut() {
60                    if !p.test(ctxt, value) {
61                        return false;
62                    }
63                }
64                return true;
65            }
66        }
67    }
68}