use crate::rule::{EvalFn, ExecuteFn, Rule, RuleContext, RuleError, RuleResult};
pub struct ChainRule {
child: Option<Box<dyn Rule>>,
eval_fn: Option<EvalFn>,
pre_execute_fn: Option<ExecuteFn>,
execute_fn: Option<ExecuteFn>,
post_execute_fn: Option<ExecuteFn>,
}
impl ChainRule {
pub fn new() -> Self {
ChainRule {
child: None,
eval_fn: None,
pre_execute_fn: None,
execute_fn: None,
post_execute_fn: None,
}
}
pub fn builder() -> ChainRuleBuilder {
ChainRuleBuilder::new()
}
pub fn set_eval_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&RuleContext) -> RuleResult<bool> + 'static,
{
self.eval_fn = Some(Box::new(f));
self
}
pub fn set_pre_execute_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.pre_execute_fn = Some(Box::new(f));
self
}
pub fn set_execute_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.execute_fn = Some(Box::new(f));
self
}
pub fn set_post_execute_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.post_execute_fn = Some(Box::new(f));
self
}
pub fn set_child(&mut self, child: Box<dyn Rule>) -> RuleResult<&mut Self> {
if self.child.is_some() {
return Err(RuleError::TooManyChildren {
max: 1,
attempted: 2,
});
}
self.child = Some(child);
Ok(self)
}
}
impl Rule for ChainRule {
fn evaluate(&self, context: &RuleContext) -> RuleResult<bool> {
match &self.eval_fn {
Some(f) => f(context),
None => Ok(true), }
}
fn execute(&mut self, context: &mut RuleContext) -> RuleResult<()> {
if let Some(f) = &self.pre_execute_fn {
f(context)?;
}
if let Some(f) = &self.execute_fn {
f(context)?;
}
if let Some(f) = &self.post_execute_fn {
f(context)?;
}
Ok(())
}
fn children(&self) -> &[Box<dyn Rule>] {
match &self.child {
Some(child) => std::slice::from_ref(child),
None => &[],
}
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Rule>> {
unimplemented!("ChainRule uses custom child execution in fire()")
}
fn add_child(&mut self, child: Box<dyn Rule>) -> RuleResult<()> {
if self.child.is_some() {
return Err(RuleError::TooManyChildren {
max: 1,
attempted: 2,
});
}
self.child = Some(child);
Ok(())
}
fn fire(&mut self, context: &mut RuleContext) -> RuleResult<bool> {
if self.evaluate(context)? {
self.execute(context)?;
if let Some(child) = &mut self.child {
child.fire(context)?;
}
Ok(true)
} else {
Ok(false)
}
}
}
impl Default for ChainRule {
fn default() -> Self {
Self::new()
}
}
pub struct ChainRuleBuilder {
rule: ChainRule,
}
impl ChainRuleBuilder {
pub fn new() -> Self {
ChainRuleBuilder {
rule: ChainRule::new(),
}
}
pub fn eval_fn<F>(mut self, f: F) -> Self
where
F: Fn(&RuleContext) -> RuleResult<bool> + 'static,
{
self.rule.set_eval_fn(f);
self
}
pub fn pre_execute_fn<F>(mut self, f: F) -> Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.rule.set_pre_execute_fn(f);
self
}
pub fn execute_fn<F>(mut self, f: F) -> Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.rule.set_execute_fn(f);
self
}
pub fn post_execute_fn<F>(mut self, f: F) -> Self
where
F: Fn(&mut RuleContext) -> RuleResult<()> + 'static,
{
self.rule.set_post_execute_fn(f);
self
}
pub fn child(mut self, child: Box<dyn Rule>) -> RuleResult<Self> {
self.rule.add_child(child)?;
Ok(self)
}
pub fn build(self) -> ChainRule {
self.rule
}
}
impl Default for ChainRuleBuilder {
fn default() -> Self {
Self::new()
}
}