1use crate::{CollectionDiffKind, CollectionDiffTrace, NodeId, collection::StoredDiff};
2use core::any::Any;
3use std::collections::{BTreeMap, BTreeSet};
4
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct Added<T> {
8 pub value: T,
10}
11
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub struct Removed<T> {
15 pub value: T,
17}
18
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct Unchanged<T> {
22 pub value: T,
24}
25
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub struct Updated<K, V> {
29 pub key: K,
31 pub previous: V,
33 pub current: V,
35}
36
37#[derive(Clone, Debug, Eq, PartialEq)]
38pub struct SetDiff<K> {
40 pub added: Vec<Added<K>>,
42 pub removed: Vec<Removed<K>>,
44 pub unchanged: Vec<Unchanged<K>>,
46}
47
48impl<K> SetDiff<K>
49where
50 K: Clone + Ord,
51{
52 pub(crate) fn between(previous: &BTreeSet<K>, current: &BTreeSet<K>) -> Self {
53 Self {
54 added: current
55 .difference(previous)
56 .cloned()
57 .map(|value| Added { value })
58 .collect(),
59 removed: previous
60 .difference(current)
61 .cloned()
62 .map(|value| Removed { value })
63 .collect(),
64 unchanged: previous
65 .intersection(current)
66 .cloned()
67 .map(|value| Unchanged { value })
68 .collect(),
69 }
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.added.is_empty() && self.removed.is_empty()
75 }
76}
77
78impl<K> StoredDiff for SetDiff<K>
79where
80 K: Clone + Ord + Send + Sync + 'static,
81{
82 fn clone_box(&self) -> Box<dyn StoredDiff> {
83 Box::new(self.clone())
84 }
85
86 fn trace(&self, node: NodeId) -> CollectionDiffTrace {
87 CollectionDiffTrace {
88 node,
89 kind: CollectionDiffKind::Set,
90 added: self.added.len(),
91 removed: self.removed.len(),
92 updated: 0,
93 unchanged: self.unchanged.len(),
94 }
95 }
96
97 fn as_any(&self) -> &dyn Any {
98 self
99 }
100}
101
102#[derive(Clone, Debug, Eq, PartialEq)]
103pub struct MapDiff<K, V> {
105 pub added: Vec<Added<(K, V)>>,
107 pub removed: Vec<Removed<(K, V)>>,
109 pub updated: Vec<Updated<K, V>>,
111 pub unchanged: Vec<Unchanged<(K, V)>>,
113}
114
115impl<K, V> MapDiff<K, V>
116where
117 K: Clone + Ord,
118 V: Clone + PartialEq,
119{
120 pub(crate) fn between(previous: &BTreeMap<K, V>, current: &BTreeMap<K, V>) -> Self {
121 let mut added = Vec::new();
122 let mut removed = Vec::new();
123 let mut updated = Vec::new();
124 let mut unchanged = Vec::new();
125
126 for (key, previous_value) in previous {
127 match current.get(key) {
128 Some(current_value) if current_value == previous_value => {
129 unchanged.push(Unchanged {
130 value: (key.clone(), current_value.clone()),
131 });
132 }
133 Some(current_value) => updated.push(Updated {
134 key: key.clone(),
135 previous: previous_value.clone(),
136 current: current_value.clone(),
137 }),
138 None => removed.push(Removed {
139 value: (key.clone(), previous_value.clone()),
140 }),
141 }
142 }
143
144 for (key, value) in current {
145 if !previous.contains_key(key) {
146 added.push(Added {
147 value: (key.clone(), value.clone()),
148 });
149 }
150 }
151
152 Self {
153 added,
154 removed,
155 updated,
156 unchanged,
157 }
158 }
159
160 pub fn is_empty(&self) -> bool {
162 self.added.is_empty() && self.removed.is_empty() && self.updated.is_empty()
163 }
164}
165
166impl<K, V> StoredDiff for MapDiff<K, V>
167where
168 K: Clone + Ord + Send + Sync + 'static,
169 V: Clone + PartialEq + Send + Sync + 'static,
170{
171 fn clone_box(&self) -> Box<dyn StoredDiff> {
172 Box::new(self.clone())
173 }
174
175 fn trace(&self, node: NodeId) -> CollectionDiffTrace {
176 CollectionDiffTrace {
177 node,
178 kind: CollectionDiffKind::Map,
179 added: self.added.len(),
180 removed: self.removed.len(),
181 updated: self.updated.len(),
182 unchanged: self.unchanged.len(),
183 }
184 }
185
186 fn as_any(&self) -> &dyn Any {
187 self
188 }
189}