dredd_rs/rule/
best_first_rule.rs

1use crate::rule::{EvalFn, ExecuteFn, Rule, RuleContext, RuleResult};
2
3/// BestFirstRule represents a rule that executes the first child that evaluates to true.
4/// If no child evaluates to true, it tries siblings until one succeeds.
5///
6/// # Example
7///
8/// ```rust
9/// use dredd_rs::rule::*;
10///
11/// let mut rule = BestFirstRule::new();
12/// rule.set_eval_fn(|context| {
13///     context.get_bool("should_execute")
14/// });
15/// rule.set_execute_fn(|context| {
16///     context.set_bool("executed", true);
17///     Ok(())
18/// });
19///
20/// let mut context = RuleContext::new();
21/// context.set_bool("should_execute", true);
22///
23/// let result = rule.fire(&mut context).unwrap();
24/// assert!(result);
25/// ```
26pub struct BestFirstRule {
27    children: Vec<Box<dyn Rule>>,
28    eval_fn: Option<EvalFn>,
29    pre_execute_fn: Option<ExecuteFn>,
30    execute_fn: Option<ExecuteFn>,
31    post_execute_fn: Option<ExecuteFn>,
32}
33
34impl BestFirstRule {
35    /// Create a new BestFirstRule
36    pub fn new() -> Self {
37        BestFirstRule {
38            children: Vec::new(),
39            eval_fn: None,
40            pre_execute_fn: None,
41            execute_fn: None,
42            post_execute_fn: None,
43        }
44    }
45
46    /// Set the evaluation function
47    pub fn set_eval_fn<F>(&mut self, f: F) -> &mut Self
48    where
49        F: Fn(&RuleContext) -> RuleResult<bool> + 'static,
50    {
51        self.eval_fn = Some(Box::new(f));
52        self
53    }
54
55    /// Set the pre-execution function
56    pub fn set_pre_execute_fn<F>(&mut self, f: F) -> &mut Self
57    where
58        F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
59    {
60        self.pre_execute_fn = Some(Box::new(f));
61        self
62    }
63
64    /// Set the execution function
65    pub fn set_execute_fn<F>(&mut self, f: F) -> &mut Self
66    where
67        F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
68    {
69        self.execute_fn = Some(Box::new(f));
70        self
71    }
72
73    /// Set the post-execution function
74    pub fn set_post_execute_fn<F>(&mut self, f: F) -> &mut Self
75    where
76        F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
77    {
78        self.post_execute_fn = Some(Box::new(f));
79        self
80    }
81}
82
83impl Rule for BestFirstRule {
84    fn evaluate(&self, context: &RuleContext) -> RuleResult<bool> {
85        match &self.eval_fn {
86            Some(f) => f(context),
87            None => Ok(true), // Default: always evaluate to true
88        }
89    }
90
91    fn execute(&mut self, context: &mut RuleContext) -> RuleResult<()> {
92        // Pre-execute
93        if let Some(f) = &self.pre_execute_fn {
94            f(context)?;
95        }
96
97        // Main execute
98        if let Some(f) = &self.execute_fn {
99            f(context)?;
100        }
101
102        // Post-execute
103        if let Some(f) = &self.post_execute_fn {
104            f(context)?;
105        }
106
107        Ok(())
108    }
109
110    fn children(&self) -> &[Box<dyn Rule>] {
111        &self.children
112    }
113
114    fn children_mut(&mut self) -> &mut Vec<Box<dyn Rule>> {
115        &mut self.children
116    }
117
118    fn add_child(&mut self, child: Box<dyn Rule>) -> RuleResult<()> {
119        self.children.push(child);
120        Ok(())
121    }
122
123    /// Custom fire implementation for BestFirstRule that implements best-first execution
124    fn fire(&mut self, context: &mut RuleContext) -> RuleResult<bool> {
125        if self.evaluate(context)? {
126            self.execute(context)?;
127
128            // Execute the first child that evaluates to true
129            for child in &mut self.children {
130                if child.evaluate(context)? {
131                    child.fire(context)?;
132                    return Ok(true);
133                }
134            }
135
136            Ok(true)
137        } else {
138            Ok(false)
139        }
140    }
141}
142
143impl Default for BestFirstRule {
144    fn default() -> Self {
145        Self::new()
146    }
147}