1use serde::{Deserialize, Serialize};
4use std::collections::{BTreeMap, BTreeSet};
5
6#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
8#[serde(rename_all = "snake_case")]
9pub enum ItemDiff<T> {
10 Ignore,
12 Set(T),
14 Unset,
16}
17
18impl<T> ItemDiff<T> {
19 pub fn set<I: Into<T>>(i: I) -> Self {
20 Self::Set(i.into())
21 }
22}
23
24impl<T> Default for ItemDiff<T> {
25 fn default() -> Self {
26 ItemDiff::Ignore
27 }
28}
29
30pub trait ItemDiffExt<T> {
31 fn apply(self, prev: T) -> T;
33}
34
35impl<T> ItemDiffExt<Option<T>> for ItemDiff<T> {
36 fn apply(self, prev: Option<T>) -> Option<T> {
37 match self {
38 ItemDiff::Ignore => prev,
39 ItemDiff::Set(t) => Some(t),
40 ItemDiff::Unset => None,
41 }
42 }
43}
44
45impl<T> ItemDiffExt<&mut Option<T>> for ItemDiff<T> {
46 fn apply(self, prev: &mut Option<T>) -> &mut Option<T> {
47 match self {
48 ItemDiff::Ignore => {}
49 ItemDiff::Set(t) => {
50 *prev = Some(t);
51 }
52 ItemDiff::Unset => {
53 *prev = None;
54 }
55 }
56 prev
57 }
58}
59
60impl<T: Default> ItemDiffExt<T> for ItemDiff<T> {
61 fn apply(self, prev: T) -> T {
62 match self {
63 ItemDiff::Ignore => prev,
64 ItemDiff::Set(t) => t,
65 ItemDiff::Unset => T::default(),
66 }
67 }
68}
69
70#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
72pub enum SetDiff<T> {
73 Add(T),
75 Remove(T),
77 Ignore,
79}
80
81impl<T> Default for SetDiff<T> {
82 fn default() -> Self {
83 SetDiff::Ignore
84 }
85}
86
87pub trait SetDiffExt<T> {
88 fn apply<I: IntoIterator<Item = SetDiff<T>>>(&mut self, iter: I);
92}
93
94impl<T: Ord> SetDiffExt<T> for BTreeSet<T> {
95 fn apply<I: IntoIterator<Item = SetDiff<T>>>(&mut self, iter: I) {
96 iter.into_iter().for_each(|item| match item {
97 SetDiff::Add(t) => {
98 self.insert(t);
99 }
100 SetDiff::Remove(t) => {
101 self.remove(&t);
102 }
103 _ => {}
104 });
105 }
106}
107
108#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
110#[serde(rename_all = "snake_case")]
111pub enum MapDiff<K, V> {
112 Add { key: K, value: V },
114 Remove(K),
116 Ignore,
118}
119
120impl<K, V> Default for MapDiff<K, V> {
121 fn default() -> Self {
122 MapDiff::Ignore
123 }
124}
125
126pub trait MapDiffExt<K, V> {
127 fn apply<I: IntoIterator<Item = MapDiff<K, V>>>(&mut self, iter: I);
131}
132
133impl<K: Ord, V> MapDiffExt<K, V> for BTreeMap<K, V> {
134 fn apply<I: IntoIterator<Item = MapDiff<K, V>>>(&mut self, iter: I) {
135 iter.into_iter().for_each(|item| match item {
136 MapDiff::Add { key, value } => {
137 self.insert(key, value);
138 }
139 MapDiff::Remove(key) => {
140 self.remove(&key);
141 }
142 _ => {}
143 });
144 }
145}
146
147#[cfg(test)]
148mod test {
149 use super::*;
150
151 #[test]
152 fn json_serde() {
153 let variants = [
154 (ItemDiff::Ignore, "\"ignore\""),
155 (ItemDiff::Set(true), "{\"set\":true}"),
156 (ItemDiff::Unset, "\"unset\""),
157 ];
158
159 for (v, s) in variants.iter() {
160 let string = serde_json::to_string(v).unwrap();
161 assert_eq!(&string, s);
162 let value: ItemDiff<bool> = serde_json::from_str(&string).unwrap();
163 assert_eq!(value, *v);
164 }
165 }
166
167 #[test]
168 fn bincode_serde() {
169 let variants = [
170 (ItemDiff::Ignore, vec![0, 0, 0, 0]),
171 (ItemDiff::Set(true), vec![1, 0, 0, 0, 1]),
172 (ItemDiff::Unset, vec![2, 0, 0, 0]),
173 ];
174
175 for (v, s) in variants.iter() {
176 let data = bincode::serialize(v).unwrap();
177 assert_eq!(&data, s);
178 let value: ItemDiff<bool> = bincode::deserialize(&data).unwrap();
179 assert_eq!(value, *v);
180 }
181 }
182}