diffus/diffable_impls/
set.rs

1use crate::{
2    edit::{set, Edit},
3    Diffable,
4};
5
6macro_rules! set_impl {
7    ($(($typ:ident, $key_constraint:ident, $diff_type:ident)),*) => {
8        $(
9            impl<'a, K: Diffable<'a> + Eq + $key_constraint + 'a> Diffable<'a> for $typ<K> {
10                type Diff = $diff_type<&'a K, set::Edit<'a, K>>;
11
12                fn diff(&'a self, other: &'a Self) -> Edit<Self> {
13                    let intersection = self
14                        .iter()
15                        .filter(|k| other.contains(*k));
16
17                    let unique_self = self.iter().filter(|k| !other.contains(*k));
18
19                    let unique_other = other.iter().filter(|k| !self.contains(*k));
20
21                    let value_diffs = unique_other
22                        .map(|k| (k, set::Edit::Insert(k)))
23                        .chain(unique_self.map(|k| (k, set::Edit::Remove(k))))
24                        .chain(intersection.map(|k| (k, set::Edit::Copy(k))))
25                        .collect::<$diff_type<_, _>>();
26
27                    if value_diffs.iter().any(|(_, edit)| !edit.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, BTreeSet, HashMap, HashSet},
40    hash::Hash,
41};
42set_impl! {
43    (BTreeSet, Ord, BTreeMap),
44    (HashSet, Hash, HashMap)
45}
46
47#[cfg(feature = "indexmap-impl")]
48use indexmap::{IndexMap, IndexSet};
49#[cfg(feature = "indexmap-impl")]
50set_impl! { (IndexSet, Hash, IndexMap) }
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn example() {
58        let unity: std::collections::HashSet<_, _> = [1, 2, 3].iter().cloned().collect();
59        let not_unity: std::collections::HashSet<_, _> = [1, 2, 4].iter().cloned().collect();
60
61        if let Edit::Change(diff) = unity.diff(&not_unity) {
62            assert!(diff[&1].is_copy());
63            assert!(diff[&2].is_copy());
64            assert!(diff[&3].is_remove());
65            assert_eq!(diff[&4].insert().unwrap(), &4);
66        } else {
67            unreachable!()
68        }
69    }
70}