1use crate::Diff;
5use serde::Deserialize;
6use serde::Serialize;
7use std::collections::HashMap;
8use std::collections::HashSet;
9use std::fmt::Debug;
10use std::fmt::Formatter;
11
12use std::hash::Hash;
13use std::iter::empty;
14
15#[derive(Clone, PartialEq, Serialize, Deserialize)]
17#[serde(untagged)]
18pub enum InnerValue<K, V: Diff> {
19 Change {
21 #[serde(rename = "c:k")]
22 key: K,
23 #[serde(rename = "c:v")]
24 value: <V as Diff>::Type,
25 },
26 Add {
28 #[serde(rename = "a:k")]
29 key: K,
30 #[serde(rename = "a:v")]
31 value: <V as Diff>::Type,
32 },
33 Remove {
35 #[serde(rename = "r:k")]
36 key: K,
37 },
38}
39
40#[derive(Clone, PartialEq, Serialize, Deserialize)]
43#[serde(transparent)]
44pub struct DiffHashMap<K: Diff, V: Diff>(
45 #[serde(skip_serializing_if = "Option::is_none")] pub Option<Vec<InnerValue<K, V>>>,
46);
47
48impl<K, V> Diff for HashMap<K, V>
50where
51 K: Clone + Debug + PartialEq + Eq + Hash + Diff + for<'de> Deserialize<'de> + Serialize,
52 V: Clone + Debug + PartialEq + Diff + for<'de> Deserialize<'de> + Serialize,
53{
54 type Type = DiffHashMap<K, V>;
56
57 fn diff(&self, other: &Self) -> crate::Result<Self::Type> {
59 let old: HashSet<&K> = self.keys().collect();
60 let new: HashSet<&K> = other.keys().collect();
61
62 let changed_keys = old.intersection(&new).filter(|k| self[k] != other[k]);
63 let removed_keys = old.difference(&new);
64 let added_keys = new.difference(&old);
65
66 let mut changes: Vec<InnerValue<K, V>> = Vec::new();
67
68 for key in changed_keys {
69 let (old_val, new_val): (&V, &V) = (&self[key], &other[key]);
70
71 let diff = old_val.diff(new_val)?;
72
73 changes.push(InnerValue::Change {
74 key: (*key).clone(),
75 value: diff,
76 });
77 }
78 for key in added_keys {
79 changes.push(InnerValue::Add {
80 key: (*key).clone(),
81 value: other[key].clone().into_diff()?,
82 });
83 }
84 for key in removed_keys {
85 changes.push(InnerValue::Remove { key: (*key).clone() });
86 }
87
88 Ok(DiffHashMap(if changes.is_empty() { None } else { Some(changes) }))
89 }
90
91 fn merge(&self, diff: Self::Type) -> crate::Result<Self> {
93 let mut new = self.clone();
94
95 for change in diff.0.into_iter().flatten() {
96 match change {
97 InnerValue::Change { key, value } => {
98 let fake: &mut V = &mut *new.get_mut(&key).expect("Failed to get value");
99
100 *fake = <V>::from_diff(value)?;
101 }
102 InnerValue::Add { key, value } => {
103 new.insert(key, <V>::from_diff(value)?);
104 }
105 InnerValue::Remove { key } => {
106 new.remove(&key);
107 }
108 }
109 }
110
111 Ok(new)
112 }
113
114 fn from_diff(diff: Self::Type) -> crate::Result<Self> {
116 let mut map = Self::new();
117 if let Some(diff) = diff.0 {
118 for (idx, elm) in diff.into_iter().enumerate() {
119 match elm {
120 InnerValue::Add { key, value } => {
121 map.insert(key, <V>::from_diff(value)?);
122 }
123 _ => {
124 panic!("Unable to create Diff at index: {:?}", idx);
125 }
126 }
127 }
128 }
129
130 Ok(map)
131 }
132
133 fn into_diff(self) -> crate::Result<Self::Type> {
135 let mut changes: Vec<InnerValue<K, V>> = Vec::new();
136 for (key, val) in self {
137 changes.push(InnerValue::Add {
138 key,
139 value: val.into_diff()?,
140 });
141 }
142
143 Ok(DiffHashMap(if changes.is_empty() { None } else { Some(changes) }))
144 }
145}
146
147impl<K, V> Debug for DiffHashMap<K, V>
149where
150 K: Debug + Diff,
151 V: Debug + Diff,
152{
153 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
154 write!(f, "DiffHashMap")?;
155
156 let mut buf = f.debug_list();
157
158 if let Some(val) = &self.0 {
159 buf.entries(val.iter());
160 } else {
161 buf.entries(empty::<Vec<InnerValue<K, V>>>());
162 }
163 buf.finish()
164 }
165}
166
167impl<K, V> Default for DiffHashMap<K, V>
169where
170 K: Diff,
171 V: Diff,
172{
173 fn default() -> Self {
174 DiffHashMap(None)
175 }
176}
177
178impl<K, V> Debug for InnerValue<K, V>
180where
181 K: Debug + Diff,
182 V: Debug + Diff,
183{
184 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
185 match &self {
186 Self::Change { key, value } => f
187 .debug_struct("Change")
188 .field("key", key)
189 .field("value", value)
190 .finish(),
191 Self::Add { key, value } => f.debug_struct("Add").field("key", key).field("value", value).finish(),
192 Self::Remove { key } => f.debug_struct("Remove").field("key", key).finish(),
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use std::collections::HashMap;
201
202 macro_rules! map {
204 ($($key:expr => $val:expr),* $(,)?) => {{
205 let mut map = HashMap::new();
206 $( map.insert($key, $val); )*
207 map
208 }}
209 }
210
211 #[test]
212 fn test_hashmap_diff() {
213 let m0: HashMap<String, usize> = map! {
214 "test".into() => 300usize,
215 "foo".into() => 10usize,
216 "bar".into() => 20usize,
217 "baz".into() => 1usize,
218 };
219
220 let m1: HashMap<String, usize> = map! {
221 "test".into() => 300usize,
222 "foo".into() => 0usize,
223 "bar".into() => 20usize,
224 "quux".into() => 10usize,
225 };
226
227 let diff = m0.diff(&m1).unwrap();
228
229 let expected: DiffHashMap<String, usize> = DiffHashMap(Some(vec![
230 InnerValue::Change {
231 key: "foo".into(),
232 value: 0usize.into_diff().unwrap(),
233 },
234 InnerValue::Add {
235 key: "quux".into(),
236 value: 10usize.into_diff().unwrap(),
237 },
238 InnerValue::Remove { key: "baz".into() },
239 ]));
240
241 assert_eq!(expected, diff);
242
243 let m2 = m0.merge(diff).unwrap();
244
245 assert_eq!(m1, m2);
246 }
247}