1use std::ops::AddAssign;
9
10pub trait Reducer<T>: Send + Sync {
12 fn reduce(&self, current: &mut T, update: T);
14}
15
16pub struct Append;
18impl<T: Send + Sync> Reducer<Vec<T>> for Append {
19 fn reduce(&self, current: &mut Vec<T>, update: Vec<T>) {
20 current.extend(update);
21 }
22}
23
24pub struct Add;
26impl<T> Reducer<T> for Add
27where
28 T: AddAssign + Send + Sync,
29{
30 fn reduce(&self, current: &mut T, update: T) {
31 *current += update;
32 }
33}
34
35pub struct LastValue;
40impl<T: Send + Sync> Reducer<Option<T>> for LastValue {
41 fn reduce(&self, current: &mut Option<T>, update: Option<T>) {
42 if let Some(v) = update {
43 *current = Some(v);
44 }
45 }
46}
47
48pub struct Merge;
50impl Reducer<serde_json::Value> for Merge {
51 fn reduce(&self, current: &mut serde_json::Value, update: serde_json::Value) {
52 crate::state::__merge_json(current, update);
53 }
54}
55
56pub struct Custom<F>(pub F);
60impl<T, F> Reducer<T> for Custom<F>
61where
62 T: Send + Sync,
63 F: Fn(&mut T, T) + Send + Sync,
64{
65 fn reduce(&self, current: &mut T, update: T) {
66 (self.0)(current, update);
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn append_extends_vec() {
76 let mut v = vec![1, 2];
77 Append.reduce(&mut v, vec![3, 4]);
78 assert_eq!(v, vec![1, 2, 3, 4]);
79 }
80
81 #[test]
82 fn add_increments() {
83 let mut n = 5u32;
84 Add.reduce(&mut n, 3);
85 assert_eq!(n, 8);
86 }
87
88 #[test]
89 fn last_value_some_overwrites() {
90 let mut o: Option<&str> = Some("old");
91 LastValue.reduce(&mut o, Some("new"));
92 assert_eq!(o, Some("new"));
93 }
94
95 #[test]
96 fn last_value_none_keeps() {
97 let mut o: Option<&str> = Some("keep");
98 LastValue.reduce(&mut o, None);
99 assert_eq!(o, Some("keep"));
100 }
101
102 #[test]
103 fn merge_deep_merges_json() {
104 let mut t = serde_json::json!({"a": 1});
105 Merge.reduce(&mut t, serde_json::json!({"b": 2}));
106 assert_eq!(t, serde_json::json!({"a": 1, "b": 2}));
107 }
108
109 #[test]
110 fn custom_closure_applies() {
111 let mut s = String::from("hello");
112 Custom(|cur: &mut String, upd: String| cur.push_str(&upd)).reduce(&mut s, " world".into());
113 assert_eq!(s, "hello world");
114 }
115}