mappy_core/
operators.rs

1//! Value merge operators for maplets
2//! 
3//! Implements the associative and commutative binary operators (⊕) that
4//! define how values are merged when keys collide in the maplet.
5
6use std::collections::HashSet;
7use std::hash::Hash;
8use crate::MapletResult;
9
10/// Trait for merge operators that define how values are combined
11pub trait MergeOperator<V>: Clone + Send + Sync {
12    /// Merge two values using the operator ⊕
13    /// 
14    /// # Errors
15    /// 
16    /// Returns an error if the merge operation fails
17    fn merge(&self, left: V, right: V) -> MapletResult<V>;
18    
19    /// Get the identity element for this operator
20    fn identity(&self) -> V;
21    
22    /// Check if the operator is associative
23    fn is_associative(&self) -> bool {
24        true // Most operators are associative
25    }
26    
27    /// Check if the operator is commutative
28    fn is_commutative(&self) -> bool {
29        true // Most operators are commutative
30    }
31}
32
33/// Counter operator for counting use cases (addition)
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
35pub struct CounterOperator;
36
37impl MergeOperator<u64> for CounterOperator {
38    fn merge(&self, left: u64, right: u64) -> MapletResult<u64> {
39        Ok(left.saturating_add(right))
40    }
41    
42    fn identity(&self) -> u64 {
43        0
44    }
45}
46
47impl MergeOperator<u32> for CounterOperator {
48    fn merge(&self, left: u32, right: u32) -> MapletResult<u32> {
49        Ok(left.saturating_add(right))
50    }
51    
52    fn identity(&self) -> u32 {
53        0
54    }
55}
56
57impl MergeOperator<i64> for CounterOperator {
58    fn merge(&self, left: i64, right: i64) -> MapletResult<i64> {
59        Ok(left.saturating_add(right))
60    }
61    
62    fn identity(&self) -> i64 {
63        0
64    }
65}
66
67/// Set operator for set-valued maps (union)
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
69pub struct SetOperator;
70
71impl<T: Clone + Hash + Eq> MergeOperator<HashSet<T>> for SetOperator {
72    fn merge(&self, mut left: HashSet<T>, right: HashSet<T>) -> MapletResult<HashSet<T>> {
73        left.extend(right);
74        Ok(left)
75    }
76    
77    fn identity(&self) -> HashSet<T> {
78        HashSet::new()
79    }
80}
81
82/// String operator for string-valued maps (replacement)
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
84pub struct StringOperator;
85
86impl MergeOperator<String> for StringOperator {
87    fn merge(&self, _left: String, right: String) -> MapletResult<String> {
88        // For strings, we'll use the right value (replacement semantics)
89        Ok(right)
90    }
91    
92    fn identity(&self) -> String {
93        String::new()
94    }
95}
96
97/// Max operator for tracking maximum values
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
99pub struct MaxOperator;
100
101impl MergeOperator<u64> for MaxOperator {
102    fn merge(&self, left: u64, right: u64) -> MapletResult<u64> {
103        Ok(left.max(right))
104    }
105    
106    fn identity(&self) -> u64 {
107        0
108    }
109}
110
111impl MergeOperator<f64> for MaxOperator {
112    fn merge(&self, left: f64, right: f64) -> MapletResult<f64> {
113        Ok(left.max(right))
114    }
115    
116    fn identity(&self) -> f64 {
117        f64::NEG_INFINITY
118    }
119}
120
121/// Min operator for tracking minimum values
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
123pub struct MinOperator;
124
125impl MergeOperator<u64> for MinOperator {
126    fn merge(&self, left: u64, right: u64) -> MapletResult<u64> {
127        Ok(left.min(right))
128    }
129    
130    fn identity(&self) -> u64 {
131        u64::MAX
132    }
133}
134
135impl MergeOperator<f64> for MinOperator {
136    fn merge(&self, left: f64, right: f64) -> MapletResult<f64> {
137        Ok(left.min(right))
138    }
139    
140    fn identity(&self) -> f64 {
141        f64::INFINITY
142    }
143}
144
145/// Custom operator that allows user-defined merge logic
146#[derive(Clone)]
147pub struct CustomOperator<F> {
148    #[allow(dead_code)]
149    merge_fn: F,
150}
151
152impl<F> CustomOperator<F> {
153    /// Create a new custom operator
154    pub const fn new(merge_fn: F) -> Self {
155        Self {
156            merge_fn,
157        }
158    }
159}
160
161/// String concatenation operator
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct StringConcatOperator;
164
165impl MergeOperator<String> for StringConcatOperator {
166    fn merge(&self, left: String, right: String) -> MapletResult<String> {
167        Ok(format!("{left}{right}"))
168    }
169    
170    fn identity(&self) -> String {
171        String::new()
172    }
173}
174
175/// Vector concatenation operator
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub struct VectorConcatOperator;
178
179impl<T: Clone> MergeOperator<Vec<T>> for VectorConcatOperator {
180    fn merge(&self, mut left: Vec<T>, right: Vec<T>) -> MapletResult<Vec<T>> {
181        left.extend(right);
182        Ok(left)
183    }
184    
185    fn identity(&self) -> Vec<T> {
186        Vec::new()
187    }
188}
189
190/// Boolean OR operator
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192pub struct BoolOrOperator;
193
194impl MergeOperator<bool> for BoolOrOperator {
195    fn merge(&self, left: bool, right: bool) -> MapletResult<bool> {
196        Ok(left || right)
197    }
198    
199    fn identity(&self) -> bool {
200        false
201    }
202}
203
204/// Boolean AND operator
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
206pub struct BoolAndOperator;
207
208impl MergeOperator<bool> for BoolAndOperator {
209    fn merge(&self, left: bool, right: bool) -> MapletResult<bool> {
210        Ok(left && right)
211    }
212    
213    fn identity(&self) -> bool {
214        true
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221    use std::collections::HashSet;
222
223    #[test]
224    fn test_counter_operator() {
225        let op: CounterOperator = CounterOperator;
226        
227        assert_eq!(op.merge(5u64, 3u64).unwrap(), 8);
228        assert_eq!(op.merge(0u64, 10u64).unwrap(), 10);
229        
230        // Test saturation
231        assert_eq!(op.merge(u64::MAX, 1).unwrap(), u64::MAX);
232    }
233
234    #[test]
235    fn test_set_operator() {
236        let op = SetOperator;
237        
238        let mut set1 = HashSet::new();
239        set1.insert("a".to_string());
240        set1.insert("b".to_string());
241        
242        let mut set2 = HashSet::new();
243        set2.insert("b".to_string());
244        set2.insert("c".to_string());
245        
246        let result = op.merge(set1, set2).unwrap();
247        assert_eq!(result.len(), 3);
248        assert!(result.contains("a"));
249        assert!(result.contains("b"));
250        assert!(result.contains("c"));
251    }
252
253    #[test]
254    fn test_max_operator() {
255        let op: MaxOperator = MaxOperator;
256        
257        assert_eq!(op.merge(5u64, 3u64).unwrap(), 5);
258        assert_eq!(op.merge(3u64, 5u64).unwrap(), 5);
259        assert_eq!(op.merge(5.0, 3.0).unwrap(), 5.0);
260    }
261
262    #[test]
263    fn test_min_operator() {
264        let op: MinOperator = MinOperator;
265        
266        assert_eq!(op.merge(5u64, 3u64).unwrap(), 3);
267        assert_eq!(op.merge(3u64, 5u64).unwrap(), 3);
268        assert_eq!(op.merge(5.0, 3.0).unwrap(), 3.0);
269    }
270
271    #[test]
272    fn test_string_concat_operator() {
273        let op = StringConcatOperator;
274        
275        assert_eq!(op.merge("hello".to_string(), "world".to_string()).unwrap(), "helloworld");
276        assert_eq!(op.identity(), "");
277    }
278
279    #[test]
280    fn test_vector_concat_operator() {
281        let op = VectorConcatOperator;
282        
283        let vec1 = vec![1, 2, 3];
284        let vec2 = vec![4, 5, 6];
285        let result = op.merge(vec1, vec2).unwrap();
286        assert_eq!(result, vec![1, 2, 3, 4, 5, 6]);
287    }
288
289    #[test]
290    fn test_bool_operators() {
291        let or_op = BoolOrOperator;
292        let and_op = BoolAndOperator;
293        
294        assert_eq!(or_op.merge(false, true).unwrap(), true);
295        assert_eq!(or_op.merge(false, false).unwrap(), false);
296        assert_eq!(or_op.identity(), false);
297        
298        assert_eq!(and_op.merge(true, false).unwrap(), false);
299        assert_eq!(and_op.merge(true, true).unwrap(), true);
300        assert_eq!(and_op.identity(), true);
301    }
302}