diffus/diffable_impls/
map.rs1use crate::{
2 edit::{map, Edit},
3 Diffable,
4};
5
6macro_rules! map_impl {
7 ($(($typ:ident, $key_constraint:ident)),*) => {
8 $(
9 impl<'a, K: Eq + $key_constraint + 'a, V: Diffable<'a> + 'a> Diffable<'a> for $typ<K, V> {
10 type Diff = $typ<&'a K, map::Edit<'a, V>>;
11
12 fn diff(&'a self, other: &'a Self) -> Edit<Self> {
13 let intersection = self
14 .iter()
15 .filter_map(|(k, v)| Some((k, (v, other.get(k)?))));
16
17 let unique_self = self.iter().filter(|(k, _)| !other.contains_key(*k));
18
19 let unique_other = other.iter().filter(|(k, _)| !self.contains_key(*k));
20
21 let value_diffs = unique_other
22 .map(|(k, v)| (k, map::Edit::Insert(v)))
23 .chain(unique_self.map(|(k, v)| (k, map::Edit::Remove(v))))
24 .chain(intersection.map(|(k, (self_v, other_v))| (k, self_v.diff(other_v).into())))
25 .collect::<$typ<_, _>>();
26
27 if value_diffs.values().any(|v| !v.is_copy()) {
28 Edit::Change(value_diffs)
29 } else {
30 Edit::Copy(self)
31 }
32 }
33 }
34 )*
35 }
36}
37
38use std::{
39 collections::{BTreeMap, HashMap},
40 hash::Hash,
41};
42map_impl! {
43 (BTreeMap, Ord),
44 (HashMap, Hash)
45}
46
47#[cfg(feature = "indexmap-impl")]
48use indexmap::IndexMap;
49#[cfg(feature = "indexmap-impl")]
50map_impl! { (IndexMap, Hash) }
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn example() {
58 let unity: std::collections::HashMap<_, _> =
59 [(1, 1), (2, 2), (3, 3)].iter().cloned().collect();
60 let not_unity: std::collections::HashMap<_, _> =
61 [(1, 1), (2, 3), (4, 4)].iter().cloned().collect();
62
63 if let Edit::Change(diff) = unity.diff(¬_unity) {
64 assert!(diff[&1].is_copy());
65 assert_eq!(diff[&2].change().unwrap(), &(&2, &3));
66 assert!(diff[&3].is_remove());
67 assert_eq!(diff[&4].insert().unwrap(), &4);
68 } else {
69 unreachable!()
70 }
71 }
72}