trellis_core/
collection_diff.rs1use crate::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 + 'static,
81{
82 fn clone_box(&self) -> Box<dyn StoredDiff> {
83 Box::new(self.clone())
84 }
85
86 fn as_any(&self) -> &dyn Any {
87 self
88 }
89}
90
91#[derive(Clone, Debug, Eq, PartialEq)]
92pub struct MapDiff<K, V> {
94 pub added: Vec<Added<(K, V)>>,
96 pub removed: Vec<Removed<(K, V)>>,
98 pub updated: Vec<Updated<K, V>>,
100 pub unchanged: Vec<Unchanged<(K, V)>>,
102}
103
104impl<K, V> MapDiff<K, V>
105where
106 K: Clone + Ord,
107 V: Clone + PartialEq,
108{
109 pub(crate) fn between(previous: &BTreeMap<K, V>, current: &BTreeMap<K, V>) -> Self {
110 let mut added = Vec::new();
111 let mut removed = Vec::new();
112 let mut updated = Vec::new();
113 let mut unchanged = Vec::new();
114
115 for (key, previous_value) in previous {
116 match current.get(key) {
117 Some(current_value) if current_value == previous_value => {
118 unchanged.push(Unchanged {
119 value: (key.clone(), current_value.clone()),
120 });
121 }
122 Some(current_value) => updated.push(Updated {
123 key: key.clone(),
124 previous: previous_value.clone(),
125 current: current_value.clone(),
126 }),
127 None => removed.push(Removed {
128 value: (key.clone(), previous_value.clone()),
129 }),
130 }
131 }
132
133 for (key, value) in current {
134 if !previous.contains_key(key) {
135 added.push(Added {
136 value: (key.clone(), value.clone()),
137 });
138 }
139 }
140
141 Self {
142 added,
143 removed,
144 updated,
145 unchanged,
146 }
147 }
148
149 pub fn is_empty(&self) -> bool {
151 self.added.is_empty() && self.removed.is_empty() && self.updated.is_empty()
152 }
153}
154
155impl<K, V> StoredDiff for MapDiff<K, V>
156where
157 K: Clone + Ord + 'static,
158 V: Clone + PartialEq + 'static,
159{
160 fn clone_box(&self) -> Box<dyn StoredDiff> {
161 Box::new(self.clone())
162 }
163
164 fn as_any(&self) -> &dyn Any {
165 self
166 }
167}