condition_matcher/matchers/
rule.rs

1//! Rule-based matcher implementation.
2
3use crate::{
4    condition::{Condition, ConditionMode},
5    matchable::Matchable,
6    result::{ConditionResult, MatchResult},
7    traits::{Evaluate, Matcher, Predicate},
8};
9
10/// A rule-based matcher built from programmatic conditions.
11///
12/// Use [`MatcherBuilder`](crate::builder::MatcherBuilder) for a fluent construction API.
13///
14/// # Example
15///
16/// ```rust
17/// use condition_matcher::{RuleMatcher, MatcherMode, Condition, ConditionSelector, ConditionOperator, Matcher};
18///
19/// let mut matcher: RuleMatcher<i32> = RuleMatcher::new(MatcherMode::AND);
20/// matcher.add_condition(Condition {
21///     selector: ConditionSelector::Value(42),
22///     operator: ConditionOperator::Equals,
23/// });
24///
25/// assert!(matcher.matches(&42));
26/// ```
27#[derive(Debug)]
28pub struct RuleMatcher<'a, T: Matchable> {
29    /// The logical combination mode (AND, OR, XOR).
30    pub mode: ConditionMode,
31    /// The conditions to evaluate.
32    pub conditions: Vec<Condition<'a, T>>,
33}
34
35impl<'a, T: Matchable + 'static> RuleMatcher<'a, T> {
36    /// Create a new matcher with the specified mode.
37    pub fn new(mode: ConditionMode) -> Self {
38        Self {
39            mode,
40            conditions: Vec::new(),
41        }
42    }
43
44    /// Create a new matcher with AND mode.
45    pub fn and() -> Self {
46        Self::new(ConditionMode::AND)
47    }
48
49    /// Create a new matcher with OR mode.
50    pub fn or() -> Self {
51        Self::new(ConditionMode::OR)
52    }
53
54    /// Create a new matcher with XOR mode.
55    pub fn xor() -> Self {
56        Self::new(ConditionMode::XOR)
57    }
58
59    /// Add a condition to this matcher.
60    pub fn add_condition(&mut self, condition: Condition<'a, T>) -> &mut Self {
61        self.conditions.push(condition);
62        self
63    }
64
65    /// Add multiple conditions at once.
66    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