condition_matcher/traits.rs
1//! Core traits for the condition-matcher library.
2//!
3//! This module defines the trait hierarchy that enables polymorphic matching:
4//! - [`Matcher`]: Core trait for any type that can match against a value
5//! - [`Evaluate`]: Extended trait for detailed evaluation results
6//! - [`Predicate`]: Trait for individual condition evaluation
7//! - [`MatcherExt`]: Extension trait providing batch operations
8
9use crate::{
10 condition::ConditionMode,
11 matchable::Matchable,
12 result::ConditionResult,
13};
14
15/// Core trait for any type that can match against a value.
16///
17/// This is the primary interface users interact with. Both [`RuleMatcher`](crate::matchers::RuleMatcher)
18/// and [`JsonMatcher`](crate::matchers::JsonMatcher) implement this trait.
19///
20/// # Example
21///
22/// ```rust
23/// use condition_matcher::{Matcher, MatcherBuilder};
24///
25/// let matcher = MatcherBuilder::<i32>::new()
26/// .value_equals(42)
27/// .build();
28///
29/// assert!(matcher.matches(&42));
30/// assert!(!matcher.matches(&41));
31/// ```
32pub trait Matcher<T: Matchable> {
33 /// Check if this matcher matches the given value.
34 fn matches(&self, value: &T) -> bool;
35
36 /// Get the logical combination mode (AND, OR, XOR).
37 fn mode(&self) -> ConditionMode;
38}
39
40/// Extended trait for matchers that provide detailed evaluation results.
41///
42/// Implement this trait when you need to provide detailed information about
43/// why a match succeeded or failed.
44pub trait Evaluate<T: Matchable>: Matcher<T> {
45 /// The result type for detailed evaluation.
46 type Output;
47
48 /// Evaluate with full details (field values, errors, descriptions).
49 fn evaluate(&self, value: &T) -> Self::Output;
50}
51
52/// Trait for individual condition/predicate evaluation.
53///
54/// Implemented by [`Condition`](crate::condition::Condition) to evaluate
55/// a single rule against a value.
56pub trait Predicate<T: Matchable> {
57 /// Test this predicate against a value.
58 fn test(&self, value: &T) -> bool;
59
60 /// Test with detailed result information.
61 fn test_detailed(&self, value: &T) -> ConditionResult;
62}
63
64/// Extension trait providing batch operations.
65///
66/// This trait is blanket implemented for all [`Matcher`] types, providing
67/// convenient methods for operating on collections of values.
68///
69/// # Example
70///
71/// ```rust
72/// use condition_matcher::{Matcher, MatcherExt, MatcherBuilder};
73///
74/// let matcher = MatcherBuilder::<i32>::new()
75/// .value_equals(42)
76/// .build();
77///
78/// let values = vec![40, 41, 42, 43, 42];
79/// let matches = matcher.filter(&values);
80/// assert_eq!(matches.len(), 2);
81/// ```
82pub trait MatcherExt<T: Matchable>: Matcher<T> {
83 /// Filter values, returning references to those that match.
84 fn filter<'a>(&self, values: &'a [T]) -> Vec<&'a T> {
85 values.iter().filter(|v| self.matches(v)).collect()
86 }
87
88 /// Filter values in parallel (requires `parallel` feature).
89 #[cfg(feature = "parallel")]
90 fn filter_par<'a>(&self, values: &'a [T]) -> Vec<&'a T>
91 where
92 T: Sync,
93 Self: Sync,
94 {
95 use rayon::prelude::*;
96 values.par_iter().filter(|v| self.matches(v)).collect()
97 }
98
99 /// Check all values, returning match results as a vector of booleans.
100 fn matches_all(&self, values: &[T]) -> Vec<bool> {
101 values.iter().map(|v| self.matches(v)).collect()
102 }
103
104 /// Check all values in parallel (requires `parallel` feature).
105 #[cfg(feature = "parallel")]
106 fn matches_all_par(&self, values: &[T]) -> Vec<bool>
107 where
108 T: Sync,
109 Self: Sync,
110 {
111 use rayon::prelude::*;
112 values.par_iter().map(|v| self.matches(v)).collect()
113 }
114}
115
116// Blanket implementation - any Matcher gets batch operations for free
117impl<T: Matchable, M: Matcher<T>> MatcherExt<T> for M {}
118
119// Blanket implementation - references to Matchers also implement Matcher
120impl<T: Matchable, M: Matcher<T>> Matcher<T> for &M {
121 fn matches(&self, value: &T) -> bool {
122 (*self).matches(value)
123 }
124
125 fn mode(&self) -> ConditionMode {
126 (*self).mode()
127 }
128}
129