condition_matcher/matchers/
rule.rs1use crate::{
4 condition::{Condition, ConditionMode},
5 matchable::Matchable,
6 result::{ConditionResult, MatchResult},
7 traits::{Evaluate, Matcher, Predicate},
8};
9
10#[derive(Debug)]
28pub struct RuleMatcher<'a, T: Matchable> {
29 pub mode: ConditionMode,
31 pub conditions: Vec<Condition<'a, T>>,
33}
34
35impl<'a, T: Matchable + 'static> RuleMatcher<'a, T> {
36 pub fn new(mode: ConditionMode) -> Self {
38 Self {
39 mode,
40 conditions: Vec::new(),
41 }
42 }
43
44 pub fn and() -> Self {
46 Self::new(ConditionMode::AND)
47 }
48
49 pub fn or() -> Self {
51 Self::new(ConditionMode::OR)
52 }
53
54 pub fn xor() -> Self {
56 Self::new(ConditionMode::XOR)
57 }
58
59 pub fn add_condition(&mut self, condition: Condition<'a, T>) -> &mut Self {
61 self.conditions.push(condition);
62 self
63 }
64
65 pub fn add_conditions(
67 &mut self,
68 conditions: impl IntoIterator<Item = Condition<'a, T>>,
69 ) -> &mut Self {
70 self.conditions.extend(conditions);
71 self
72 }
73}
74
75impl<'a, T: Matchable + 'static> Matcher<T> for RuleMatcher<'a, T> {
76 fn matches(&self, value: &T) -> bool {
77 let results: Vec<bool> = self.conditions.iter().map(|c| c.test(value)).collect();
78 combine_results(&results, self.mode)
79 }
80
81 fn mode(&self) -> ConditionMode {
82 self.mode
83 }
84}
85
86impl<'a, T: Matchable + 'static> Evaluate<T> for RuleMatcher<'a, T> {
87 type Output = MatchResult;
88
89 fn evaluate(&self, value: &T) -> MatchResult {
90 let condition_results: Vec<ConditionResult> =
91 self.conditions.iter().map(|c| c.test_detailed(value)).collect();
92
93 let matched = combine_results(
94 &condition_results.iter().map(|r| r.passed).collect::<Vec<_>>(),
95 self.mode,
96 );
97
98 MatchResult {
99 matched,
100 condition_results,
101 mode: self.mode,
102 }
103 }
104}
105
106fn combine_results(results: &[bool], mode: ConditionMode) -> bool {
107 match mode {
108 ConditionMode::AND => results.iter().all(|&r| r),
109 ConditionMode::OR => results.iter().any(|&r| r),
110 ConditionMode::XOR => results.iter().filter(|&&r| r).count() == 1,
111 }
112}
113