k8s_openapi/
deep_merge.rs1pub trait DeepMerge {
55 fn merge_from(&mut self, other: Self);
57}
58
59macro_rules! default_overwriting_impl {
60 () => {
61 fn merge_from(&mut self, other: Self) {
62 *self = other;
63 }
64 };
65}
66
67impl DeepMerge for bool { default_overwriting_impl! {} }
68impl DeepMerge for i32 { default_overwriting_impl! {} }
69impl DeepMerge for i64 { default_overwriting_impl! {} }
70impl DeepMerge for f64 { default_overwriting_impl! {} }
71impl DeepMerge for std::string::String { default_overwriting_impl! {} }
72impl DeepMerge for crate::ByteString { default_overwriting_impl! {} }
73impl DeepMerge for jiff::Timestamp { default_overwriting_impl! {} }
74
75impl DeepMerge for serde_json::Value {
76 fn merge_from(&mut self, other: Self) {
77 if
78 let serde_json::Value::Object(this) = self &&
79 let serde_json::Value::Object(other) = other
80 {
81 for (k, v) in other {
82 if v.is_null() {
83 this.remove(&k);
84 }
85 else {
86 this.entry(k).or_insert(serde_json::Value::Null).merge_from(v);
87 }
88 }
89
90 return;
91 }
92
93 *self = other;
94 }
95}
96
97impl<T> DeepMerge for std::boxed::Box<T> where T: DeepMerge {
98 fn merge_from(&mut self, other: Self) {
99 (**self).merge_from(*other);
100 }
101}
102
103impl<T> DeepMerge for Option<T> where T: DeepMerge {
104 fn merge_from(&mut self, other: Self) {
105 if let Some(other) = other {
106 if let Some(s) = self {
107 s.merge_from(other);
108 }
109 else {
110 *self = Some(other);
111 }
112 }
113 }
114}
115
116pub mod strategies {
118 pub mod list {
122 mod private {
123 pub trait AsOptVec {
124 type Item;
125
126 fn set_if_some(&mut self, new: Self);
127 fn as_mut_opt(&mut self) -> Option<&mut std::vec::Vec<Self::Item>>;
128 fn into_opt(self) -> Option<std::vec::Vec<Self::Item>>;
129 }
130
131 impl<T> AsOptVec for std::vec::Vec<T> {
132 type Item = T;
133
134 fn set_if_some(&mut self, new: Self) {
135 *self = new;
136 }
137
138 fn as_mut_opt(&mut self) -> Option<&mut Self> {
139 Some(self)
140 }
141
142 fn into_opt(self) -> Option<Self> {
143 Some(self)
144 }
145 }
146
147 impl<T> AsOptVec for Option<std::vec::Vec<T>> {
148 type Item = T;
149
150 fn set_if_some(&mut self, new: Self) {
151 if new.is_some() {
152 *self = new;
153 }
154 }
155
156 fn as_mut_opt(&mut self) -> Option<&mut std::vec::Vec<T>> {
157 self.as_mut()
158 }
159
160 fn into_opt(self) -> Self {
161 self
162 }
163 }
164 }
165 use private::AsOptVec;
166
167 pub fn atomic<V>(current: &mut V, new: V) where V: AsOptVec {
169 current.set_if_some(new);
170 }
171
172 pub fn map<V>(
176 current: &mut V,
177 new: V,
178 key_comparators: &[fn(&V::Item, &V::Item) -> bool],
179 merge_item: fn(&mut V::Item, V::Item),
180 )
181 where
182 V: AsOptVec,
183 {
184 if let Some(current) = current.as_mut_opt() {
185 for new_item in new.into_opt().into_iter().flatten() {
186 if let Some(current_item) = current.iter_mut().find(|current_item| key_comparators.iter().all(|&f| f(&**current_item, &new_item))) {
187 merge_item(current_item, new_item);
188 }
189 else {
190 current.push(new_item);
191 }
192 }
193 }
194 else {
195 current.set_if_some(new);
196 }
197 }
198
199 pub fn set<V>(current: &mut V, new: V) where V: AsOptVec, V::Item: PartialEq {
203 if let Some(current) = current.as_mut_opt() {
204 for item in new.into_opt().into_iter().flatten() {
205 if !current.contains(&item) {
206 current.push(item);
207 }
208 }
209 }
210 else {
211 current.set_if_some(new);
212 }
213 }
214 }
215
216 pub mod map {
220 mod private {
221 use std::collections::BTreeMap;
222
223 pub trait AsOptMap {
224 type Key;
225 type Value;
226
227 fn set_if_some(&mut self, new: Self);
228 fn as_mut_opt(&mut self) -> Option<&mut BTreeMap<Self::Key, Self::Value>>;
229 fn into_opt(self) -> Option<BTreeMap<Self::Key, Self::Value>>;
230 }
231
232 impl<K, V> AsOptMap for BTreeMap<K, V> {
233 type Key = K;
234 type Value = V;
235
236 fn set_if_some(&mut self, new: Self) {
237 *self = new;
238 }
239
240 fn as_mut_opt(&mut self) -> Option<&mut Self> {
241 Some(self)
242 }
243
244 fn into_opt(self) -> Option<Self> {
245 Some(self)
246 }
247 }
248
249 impl<K, V> AsOptMap for Option<BTreeMap<K, V>> {
250 type Key = K;
251 type Value = V;
252
253 fn set_if_some(&mut self, new: Self) {
254 if new.is_some() {
255 *self = new;
256 }
257 }
258
259 fn as_mut_opt(&mut self) -> Option<&mut BTreeMap<K, V>> {
260 self.as_mut()
261 }
262
263 fn into_opt(self) -> Self {
264 self
265 }
266 }
267 }
268 use private::AsOptMap;
269
270 pub fn atomic<M>(current: &mut M, new: M) where M: AsOptMap {
272 current.set_if_some(new);
273 }
274
275 pub fn granular<M>(current: &mut M, new: M, merge_value: fn(&mut M::Value, M::Value))
277 where
278 M: AsOptMap,
279 M::Key: Ord,
280 {
281 if let Some(current) = current.as_mut_opt() {
282 for (k, new_v) in new.into_opt().into_iter().flatten() {
283 match current.entry(k) {
284 std::collections::btree_map::Entry::Vacant(entry) => { entry.insert(new_v); }
285 std::collections::btree_map::Entry::Occupied(entry) => merge_value(entry.into_mut(), new_v),
286 }
287 }
288 }
289 else {
290 current.set_if_some(new);
291 }
292 }
293 }
294}