pub struct RuleEngine { /* private fields */ }Expand description
Runs rules against facts, as Grule’s engine does.
An engine holds a set of rules (its KnowledgeBase) plus registered functions,
methods and listeners. execute takes &self, so one engine can be
shared between threads and run concurrently.
Implementations§
Source§impl RuleEngine
impl RuleEngine
Sourcepub fn new() -> Self
pub fn new() -> Self
An engine with no rules, Grule’s default cycle limit (5000), and failed conditions counting as false.
Sourcepub fn add_rule(&mut self, rule: Rule) -> Result<(), String>
pub fn add_rule(&mut self, rule: Rule) -> Result<(), String>
Adds a rule. Fails if a rule with the same name exists.
Sourcepub fn add_rules_from_str(&mut self, grl: &str) -> Result<usize, String>
pub fn add_rules_from_str(&mut self, grl: &str) -> Result<usize, String>
Parses GRL text and adds all of its rules. Returns how many were added.
Sourcepub fn add_rules_from_file(
&mut self,
path: impl AsRef<Path>,
) -> Result<usize, String>
pub fn add_rules_from_file( &mut self, path: impl AsRef<Path>, ) -> Result<usize, String>
Loads all rules from a .grl file. Returns how many were added.
Sourcepub fn add_rules_from_dir(
&mut self,
dir: impl AsRef<Path>,
) -> Result<usize, String>
pub fn add_rules_from_dir( &mut self, dir: impl AsRef<Path>, ) -> Result<usize, String>
Loads all .grl files under dir, recursively. Returns how many rules were added.
Sourcepub fn set_max_cycles(&mut self, max_cycles: usize)
pub fn set_max_cycles(&mut self, max_cycles: usize)
Sets the maximum number of rule firings per execution before it fails
with EngineError::MaxCyclesExceeded.
Sourcepub fn set_return_err_on_failed_rule_evaluation(&mut self, enabled: bool)
pub fn set_return_err_on_failed_rule_evaluation(&mut self, enabled: bool)
By default, as in Grule, a condition that fails to evaluate (a missing field, a type error, …) is logged and treated as false. When enabled, execution stops with the error instead.
Sourcepub fn set_condition_caching(&mut self, enabled: bool)
pub fn set_condition_caching(&mut self, enabled: bool)
Reusing condition results between cycles is on by default and never changes which rules fire; turning it off is only useful for comparison and debugging.
Sourcepub fn add_listener(&mut self, listener: impl EngineListener + 'static)
pub fn add_listener(&mut self, listener: impl EngineListener + 'static)
Adds a listener notified as executions run. With any listener attached, every rule is evaluated every cycle (as in Grule) so that listeners see each evaluation.
Sourcepub fn register_function<F>(
&mut self,
name: &str,
function: F,
) -> Result<(), String>
pub fn register_function<F>( &mut self, name: &str, function: F, ) -> Result<(), String>
Makes function callable from rules as name(args...).
Sourcepub fn register_method<F>(
&mut self,
name: &str,
method: F,
) -> Result<(), String>
pub fn register_method<F>( &mut self, name: &str, method: F, ) -> Result<(), String>
Makes method callable from rules as receiver.name(args...) on any value
that has no built-in method of that name. This is the equivalent of calling a
method on a Go fact in Grule: when called as a statement in a rule’s then
scope on a fact path (Order.AddItem(x);), the method receives the stored
value and its changes persist. Anywhere else it receives a copy.
Sourcepub fn register_typed_method<T, A, R, F>(
&mut self,
name: &str,
method: F,
) -> Result<(), String>where
T: Serialize + DeserializeOwned + 'static,
A: DeserializeOwned + 'static,
R: Serialize + 'static,
F: Fn(&mut T, A) -> Result<R, String> + Send + Sync + 'static,
pub fn register_typed_method<T, A, R, F>(
&mut self,
name: &str,
method: F,
) -> Result<(), String>where
T: Serialize + DeserializeOwned + 'static,
A: DeserializeOwned + 'static,
R: Serialize + 'static,
F: Fn(&mut T, A) -> Result<R, String> + Send + Sync + 'static,
Like register_method, but the method works on your own type T, the
counterpart of a method on a Go fact struct. Around each call the receiver is
converted into T and back with serde (so T is typically the type the fact was
created from with Fact::from_serialize), the arguments are decoded into A,
and the result R is converted into a fact value.
A is a tuple for fixed arguments ((f64,), (String, i64)), () for none,
or a Vec for any number. Return Ok(()) for no result (it becomes nil).
The same name can be registered for several types; a call goes to the first
whose type the receiver converts into, then to an untyped method of that name.
Fields the receiver has that T doesn’t are kept.
let mut engine = RuleEngine::new();
engine.register_typed_method("CalculateEscrow", |loan: &mut Loan, (): ()| {
loan.escrow = loan.amount * 0.01;
Ok(())
})?;
engine.register_typed_method("Payment", |loan: &mut Loan, (rate,): (f64,)| {
Ok(loan.amount * rate / 12.0)
})?;
// GRL: then Loan.CalculateEscrow(); Loan.Monthly = Loan.Payment(0.06);Sourcepub fn execute(
&self,
facts: &mut HashMap<String, Fact>,
) -> Result<ExecutionResult, EngineError>
pub fn execute( &self, facts: &mut HashMap<String, Fact>, ) -> Result<ExecutionResult, EngineError>
Runs rules until no condition holds, as Grule does. Each cycle evaluates every
rule’s condition, then fires the highest-salience rule among those that matched
(ties go to the rule added first). Rules removed with Retract stay out for the
rest of this execution, and Complete() ends it once the current rule’s actions
have run.
Two optimizations keep this from re-evaluating everything every cycle, without changing which rules fire:
- A condition’s result is reused until a rule’s actions (or
Changed/Forget) touch a fact path it reads. Conditions usingNow(), logging or user functions/methods are always re-evaluated. - Once the cycle’s highest-salience match is found, lower rules are skipped unless evaluating them has observable effects: a listener is attached, evaluation errors are returned, or the condition logs or calls user code.
Sourcepub fn execute_with_cancel(
&self,
facts: &mut HashMap<String, Fact>,
cancel: &AtomicBool,
) -> Result<ExecutionResult, EngineError>
pub fn execute_with_cancel( &self, facts: &mut HashMap<String, Fact>, cancel: &AtomicBool, ) -> Result<ExecutionResult, EngineError>
Like execute, but stops with EngineError::Cancelled once cancel is set,
checked before each rule evaluation. Set it from another thread.
Sourcepub fn execute_with_timeout(
&self,
facts: &mut HashMap<String, Fact>,
timeout: Duration,
) -> Result<ExecutionResult, EngineError>
pub fn execute_with_timeout( &self, facts: &mut HashMap<String, Fact>, timeout: Duration, ) -> Result<ExecutionResult, EngineError>
Like execute, but stops with EngineError::TimedOut once timeout has
elapsed, checked before each rule evaluation (like a Go context deadline).
A single slow function call can still overrun it.
Sourcepub fn fetch_matching_rules(
&self,
facts: &HashMap<String, Fact>,
) -> Result<Vec<&Rule>, EngineError>
pub fn fetch_matching_rules( &self, facts: &HashMap<String, Fact>, ) -> Result<Vec<&Rule>, EngineError>
Returns the rules whose conditions currently hold, highest salience first,
without running any of them (Grule’s FetchMatchingRules).
Sourcepub fn get_knowledge_base(&self) -> &KnowledgeBase
pub fn get_knowledge_base(&self) -> &KnowledgeBase
The engine’s rules.