1use std::borrow::Borrow;
4use std::cell::UnsafeCell;
5use std::collections::hash_map::Entry;
6use std::collections::{HashMap, TryReserveError};
7use std::fmt::Debug;
8use std::hash::Hash;
9use std::iter::FusedIterator;
10use std::marker::PhantomData;
11use std::ops::{Deref, DerefMut, Index, IndexMut};
12
13use serde::Serialize;
14
15use crate::general::Snapshot;
16use crate::helper::macros::{default_impl_ref_observe, delegate_methods};
17use crate::helper::{AsDeref, AsDerefMut, ObserverState, Pointer, QuasiObserver, Succ, Unsigned, Zero};
18use crate::observe::{DefaultSpec, Observer, SerializeObserver};
19use crate::{MutationKind, Mutations, Observe, PathSegment};
20
21enum ValueState {
22 Replaced,
24 Inserted,
27 Deleted,
29}
30
31struct HashMapObserverState<K, O> {
32 mutated: bool,
33 diff: HashMap<K, ValueState>,
34 inner: UnsafeCell<HashMap<K, Box<O>>>,
38}
39
40impl<K, O> Default for HashMapObserverState<K, O> {
41 fn default() -> Self {
42 Self {
43 mutated: false,
44 diff: Default::default(),
45 inner: Default::default(),
46 }
47 }
48}
49
50impl<K, O> ObserverState for HashMapObserverState<K, O>
51where
52 K: Clone + Eq + Hash,
53 O: QuasiObserver<InnerDepth = Zero, Head: Sized>,
54{
55 type Target = HashMap<K, O::Head>;
56
57 fn invalidate(this: &mut Self, map: &Self::Target) {
58 if !this.mutated {
59 this.mutated = true;
60 for key in map.keys() {
61 this.mark_deleted(key.clone());
62 }
63 }
64 this.inner.get_mut().clear();
65 }
66}
67
68impl<K, O> HashMapObserverState<K, O>
69where
70 K: Eq + Hash,
71{
72 fn mark_deleted(&mut self, key: K) {
73 self.inner.get_mut().remove(&key);
74 match self.diff.entry(key) {
75 Entry::Occupied(mut e) => {
76 if matches!(e.get(), ValueState::Inserted) {
77 e.remove();
78 } else {
79 e.insert(ValueState::Deleted);
80 }
81 }
82 Entry::Vacant(e) => {
83 e.insert(ValueState::Deleted);
84 }
85 }
86 }
87}
88
89pub struct ExtractIf<'a, K, V, O, F>
91where
92 F: FnMut(&K, &mut V) -> bool,
93{
94 inner: std::collections::hash_map::ExtractIf<'a, K, V, F>,
95 state: Option<&'a mut HashMapObserverState<K, O>>,
96}
97
98impl<K, V, O, F> Iterator for ExtractIf<'_, K, V, O, F>
99where
100 K: Clone + Eq + Hash,
101 F: FnMut(&K, &mut V) -> bool,
102{
103 type Item = (K, V);
104
105 fn next(&mut self) -> Option<Self::Item> {
106 let (key, value) = self.inner.next()?;
107 if let Some(state) = &mut self.state {
108 state.mark_deleted(key.clone());
109 }
110 Some((key, value))
111 }
112
113 fn size_hint(&self) -> (usize, Option<usize>) {
114 self.inner.size_hint()
115 }
116}
117
118impl<K, V, O, F> FusedIterator for ExtractIf<'_, K, V, O, F>
119where
120 K: Clone + Eq + Hash,
121 F: FnMut(&K, &mut V) -> bool,
122{
123}
124
125impl<K, V, O, F> Debug for ExtractIf<'_, K, V, O, F>
126where
127 K: Debug,
128 V: Debug,
129 F: FnMut(&K, &mut V) -> bool,
130{
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 self.inner.fmt(f)
133 }
134}
135
136pub struct HashMapObserver<K, O, S: ?Sized, D = Zero> {
145 ptr: Pointer<S>,
146 state: HashMapObserverState<K, O>,
147 phantom: PhantomData<D>,
148}
149
150impl<K, O, S: ?Sized, D> Deref for HashMapObserver<K, O, S, D> {
151 type Target = Pointer<S>;
152
153 fn deref(&self) -> &Self::Target {
154 &self.ptr
155 }
156}
157
158impl<K, O, S: ?Sized, D> DerefMut for HashMapObserver<K, O, S, D> {
159 fn deref_mut(&mut self) -> &mut Self::Target {
160 std::ptr::from_mut(self).expose_provenance();
161 Pointer::invalidate(&mut self.ptr);
162 &mut self.ptr
163 }
164}
165
166impl<K, O, S: ?Sized, D> QuasiObserver for HashMapObserver<K, O, S, D>
167where
168 K: Clone + Eq + Hash,
169 D: Unsigned,
170 S: AsDeref<D, Target = HashMap<K, O::Head>>,
171 O: Observer<InnerDepth = Zero, Head: Sized>,
172{
173 type Head = S;
174 type OuterDepth = Succ<Zero>;
175 type InnerDepth = D;
176
177 fn invalidate(this: &mut Self) {
178 ObserverState::invalidate(&mut this.state, (*this.ptr).as_deref());
179 }
180}
181
182impl<K, O, S: ?Sized, D> Observer for HashMapObserver<K, O, S, D>
183where
184 D: Unsigned,
185 S: AsDeref<D, Target = HashMap<K, O::Head>>,
186 O: Observer<InnerDepth = Zero>,
187 O::Head: Sized,
188 K: Clone + Eq + Hash,
189{
190 fn observe(head: &mut Self::Head) -> Self {
191 let this = Self {
192 ptr: Pointer::new(head),
193 state: Default::default(),
194 phantom: PhantomData,
195 };
196 Pointer::register_state::<_, D>(&this.ptr, &this.state);
197 this
198 }
199
200 unsafe fn relocate(this: &mut Self, head: &mut Self::Head) {
201 Pointer::set(this, head);
202 }
203}
204
205impl<K, O, S: ?Sized, D> HashMapObserver<K, O, S, D>
206where
207 D: Unsigned,
208 S: AsDerefMut<D, Target = HashMap<K, O::Head>>,
209 O: Observer<InnerDepth = Zero> + SerializeObserver,
210 O::Head: Serialize + Sized + 'static,
211 K: Serialize + Clone + Eq + Hash + Into<PathSegment> + 'static,
212{
213 unsafe fn partial_flush(&mut self) -> Mutations {
214 let diff = std::mem::take(&mut self.state.diff);
215 let mut inner = std::mem::take(self.state.inner.get_mut());
216 let mut mutations = Mutations::new();
217 for (key, value_state) in diff {
218 match value_state {
219 ValueState::Deleted => {
220 #[cfg(feature = "delete")]
221 mutations.insert(key, MutationKind::Delete);
222 #[cfg(not(feature = "delete"))]
223 return Mutations::replace((*self).untracked_ref());
224 }
225 ValueState::Replaced | ValueState::Inserted => {
226 inner.remove(&key);
227 let value = (*self)
228 .untracked_ref()
229 .get(&key)
230 .expect("replaced key not found in observed map");
231 mutations.insert(key, Mutations::replace(value));
232 }
233 }
234 }
235 for (key, mut ob) in inner {
236 let value = self
237 .untracked_mut()
238 .get_mut(&key)
239 .expect("observer key not found in observed map");
240 unsafe { O::relocate(&mut ob, value) }
241 mutations.insert(key, unsafe { O::flush(&mut ob) });
242 }
243 mutations
244 }
245}
246
247impl<K, O, S: ?Sized, D> SerializeObserver for HashMapObserver<K, O, S, D>
248where
249 D: Unsigned,
250 S: AsDerefMut<D, Target = HashMap<K, O::Head>>,
251 O: Observer<InnerDepth = Zero> + SerializeObserver,
252 O::Head: Serialize + Sized + 'static,
253 K: Serialize + Clone + Eq + Hash + Into<PathSegment> + 'static,
254{
255 unsafe fn flush(this: &mut Self) -> Mutations {
256 if !this.state.mutated {
257 return unsafe { this.partial_flush() };
258 }
259 this.state.mutated = false;
260 this.state.diff.clear();
261 this.state.inner.get_mut().clear();
262 Mutations::replace((*this).untracked_ref())
263 }
264
265 unsafe fn flat_flush(this: &mut Self) -> (Mutations, bool) {
266 if !this.state.mutated {
267 return (unsafe { this.partial_flush() }, false);
268 }
269 this.state.mutated = false;
270 this.state.inner.get_mut().clear();
271 let mut diff = std::mem::take(&mut this.state.diff);
274 let map = (*this.ptr).as_deref();
275 let mut mutations = Mutations::new();
276 for (key, value) in map {
277 diff.remove(key);
278 mutations.insert(key.clone(), Mutations::replace(value));
279 }
280 for (key, _) in diff {
281 #[cfg(feature = "delete")]
282 mutations.insert(key, MutationKind::Delete);
283 #[cfg(not(feature = "delete"))]
284 unreachable!("delete feature is not enabled");
285 }
286 (mutations, true)
287 }
288}
289
290impl<K, O, S: ?Sized, D, V> HashMapObserver<K, O, S, D>
291where
292 D: Unsigned,
293 S: AsDerefMut<D, Target = HashMap<K, V>>,
294 O: Observer<InnerDepth = Zero, Head = V>,
295 K: Clone + Eq + Hash,
296{
297 delegate_methods! { untracked_mut() as HashMap =>
298 pub fn reserve(&mut self, additional: usize);
299 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>;
300 pub fn shrink_to_fit(&mut self);
301 pub fn shrink_to(&mut self, min_capacity: usize);
302 }
303}
304
305impl<K, O, S: ?Sized, D> HashMapObserver<K, O, S, D>
306where
307 D: Unsigned,
308 S: AsDerefMut<D, Target = HashMap<K, O::Head>>,
309 O: Observer<InnerDepth = Zero>,
310 O::Head: Sized,
311 K: Clone + Eq + Hash,
312{
313 pub fn get<Q>(&self, key: &Q) -> Option<&O>
315 where
316 K: Borrow<Q>,
317 Q: Eq + Hash + ?Sized,
318 {
319 let key_cloned = (*self.ptr).as_deref().get_key_value(key)?.0.clone();
320 let value = unsafe { Pointer::as_mut(&self.ptr) }.as_deref_mut().get_mut(key)?;
321 match unsafe { (*self.state.inner.get()).entry(key_cloned) } {
322 Entry::Occupied(occupied) => {
323 let ob = occupied.into_mut().as_mut();
324 unsafe { O::relocate(ob, value) }
325 Some(ob)
326 }
327 Entry::Vacant(vacant) => Some(vacant.insert(Box::new(O::observe(value)))),
328 }
329 }
330}
331
332impl<K, O, S: ?Sized, D> HashMapObserver<K, O, S, D>
333where
334 D: Unsigned,
335 S: AsDerefMut<D, Target = HashMap<K, O::Head>>,
336 O: Observer<InnerDepth = Zero>,
337 O::Head: Sized,
338 K: Clone + Eq + Hash,
339{
340 fn __force_all(&mut self) -> &mut HashMap<K, Box<O>> {
341 let map = (*self.ptr).as_deref_mut();
342 let inner = self.state.inner.get_mut();
343 for (key, value) in map.iter_mut() {
344 match inner.entry(key.clone()) {
345 Entry::Occupied(occupied) => {
346 let observer = occupied.into_mut().as_mut();
347 unsafe { O::relocate(observer, value) }
348 }
349 Entry::Vacant(vacant) => {
350 vacant.insert(Box::new(O::observe(value)));
351 }
352 }
353 }
354 inner
355 }
356
357 pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut O>
359 where
360 K: Borrow<Q> + Eq + Hash,
361 Q: Eq + Hash + ?Sized,
362 {
363 let key_cloned = (*self.ptr).as_deref().get_key_value(key)?.0.clone();
364 let value = (*self.ptr).as_deref_mut().get_mut(key)?;
365 match self.state.inner.get_mut().entry(key_cloned) {
366 Entry::Occupied(occupied) => {
367 let ob = occupied.into_mut().as_mut();
368 unsafe { O::relocate(ob, value) }
369 Some(ob)
370 }
371 Entry::Vacant(vacant) => Some(vacant.insert(Box::new(O::observe(value)))),
372 }
373 }
374
375 pub fn clear(&mut self) {
377 self.state.inner.get_mut().clear();
378 if (*self).untracked_ref().is_empty() {
379 self.untracked_mut().clear()
380 } else {
381 self.tracked_mut().clear()
382 }
383 }
384
385 pub fn insert(&mut self, key: K, value: O::Head) -> Option<O::Head>
387 where
388 K: Eq + Hash,
389 {
390 if self.state.mutated {
391 return self.tracked_mut().insert(key, value);
392 }
393 let key_cloned = key.clone();
394 let old_value = (*self.ptr).as_deref_mut().insert(key_cloned, value);
395 self.state.inner.get_mut().remove(&key);
396 match self.state.diff.entry(key) {
397 Entry::Occupied(mut e) => {
398 if matches!(e.get(), ValueState::Deleted) {
399 e.insert(ValueState::Replaced);
400 }
401 }
402 Entry::Vacant(e) => {
403 if old_value.is_some() {
404 e.insert(ValueState::Replaced);
405 } else {
406 e.insert(ValueState::Inserted);
407 }
408 }
409 }
410 old_value
411 }
412
413 pub fn remove<Q>(&mut self, key: &Q) -> Option<O::Head>
415 where
416 K: Borrow<Q> + Eq + Hash,
417 Q: Eq + Hash + ?Sized,
418 {
419 if self.state.mutated {
420 return self.tracked_mut().remove(key);
421 }
422 let (key, old_value) = (*self.ptr).as_deref_mut().remove_entry(key)?;
423 self.state.mark_deleted(key);
424 Some(old_value)
425 }
426
427 pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, O::Head)>
429 where
430 K: Borrow<Q> + Eq + Hash,
431 Q: Eq + Hash + ?Sized,
432 {
433 if self.state.mutated {
434 return self.tracked_mut().remove_entry(key);
435 }
436 let (key, old_value) = (*self.ptr).as_deref_mut().remove_entry(key)?;
437 self.state.mark_deleted(key.clone());
438 Some((key, old_value))
439 }
440
441 pub fn retain<F>(&mut self, mut f: F)
443 where
444 K: Eq + Hash,
445 F: FnMut(&K, &mut O::Head) -> bool,
446 {
447 self.extract_if(|k, v| !f(k, v)).for_each(drop);
448 }
449
450 pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, O::Head, O, F>
452 where
453 K: Eq + Hash,
454 F: FnMut(&K, &mut O::Head) -> bool,
455 {
456 let inner = (*self.ptr).as_deref_mut().extract_if(pred);
457 let state = if self.state.mutated {
458 None
459 } else {
460 Some(&mut self.state)
461 };
462 ExtractIf { inner, state }
463 }
464
465 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut O)> + '_
467 where
468 K: Eq + Hash,
469 {
470 self.__force_all().iter_mut().map(|(k, v)| (k, v.as_mut()))
471 }
472
473 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut O> + '_
475 where
476 K: Eq + Hash,
477 {
478 self.__force_all().values_mut().map(|v| v.as_mut())
479 }
480}
481
482impl<K, V, O, S: ?Sized, D> Debug for HashMapObserver<K, O, S, D>
483where
484 K: Clone + Eq + Hash,
485 D: Unsigned,
486 S: AsDeref<D, Target = HashMap<K, V>>,
487 O: Observer<InnerDepth = Zero, Head = V>,
488 HashMap<K, V>: Debug,
489{
490 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491 f.debug_tuple("HashMapObserver").field(&self.untracked_ref()).finish()
492 }
493}
494
495impl<K, V, O, S: ?Sized, D> PartialEq<HashMap<K, V>> for HashMapObserver<K, O, S, D>
496where
497 K: Clone + Eq + Hash,
498 D: Unsigned,
499 S: AsDeref<D, Target = HashMap<K, V>>,
500 O: Observer<InnerDepth = Zero, Head = V>,
501 HashMap<K, V>: PartialEq,
502{
503 fn eq(&self, other: &HashMap<K, V>) -> bool {
504 self.untracked_ref().eq(other)
505 }
506}
507
508impl<K1, K2, V1, V2, O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<HashMapObserver<K2, O2, S2, D2>>
509 for HashMapObserver<K1, O1, S1, D1>
510where
511 K1: Clone + Eq + Hash,
512 K2: Clone + Eq + Hash,
513 D1: Unsigned,
514 D2: Unsigned,
515 S1: AsDeref<D1, Target = HashMap<K1, V1>>,
516 S2: AsDeref<D2, Target = HashMap<K2, V2>>,
517 O1: Observer<InnerDepth = Zero, Head = V1>,
518 O2: Observer<InnerDepth = Zero, Head = V2>,
519 HashMap<K1, V1>: PartialEq<HashMap<K2, V2>>,
520{
521 fn eq(&self, other: &HashMapObserver<K2, O2, S2, D2>) -> bool {
522 self.untracked_ref().eq(other.untracked_ref())
523 }
524}
525
526impl<K, V, O, S: ?Sized, D> Eq for HashMapObserver<K, O, S, D>
527where
528 K: Clone + Eq + Hash,
529 D: Unsigned,
530 S: AsDeref<D, Target = HashMap<K, V>>,
531 O: Observer<InnerDepth = Zero, Head = V>,
532 HashMap<K, V>: Eq,
533{
534}
535
536impl<'q, K, O, S: ?Sized, D, V, Q: ?Sized> Index<&'q Q> for HashMapObserver<K, O, S, D>
537where
538 D: Unsigned,
539 S: AsDerefMut<D, Target = HashMap<K, V>>,
540 O: Observer<InnerDepth = Zero, Head = V>,
541 K: Borrow<Q> + Clone + Eq + Hash,
542 Q: Eq + Hash,
543{
544 type Output = O;
545
546 fn index(&self, index: &'q Q) -> &Self::Output {
547 self.get(index).expect("no entry found for key")
548 }
549}
550
551impl<'q, K, O, S: ?Sized, D, V, Q: ?Sized> IndexMut<&'q Q> for HashMapObserver<K, O, S, D>
552where
553 D: Unsigned,
554 S: AsDerefMut<D, Target = HashMap<K, V>>,
555 O: Observer<InnerDepth = Zero, Head = V>,
556 K: Borrow<Q> + Clone + Eq + Hash,
557 Q: Eq + Hash,
558{
559 fn index_mut(&mut self, index: &'q Q) -> &mut Self::Output {
560 self.get_mut(index).expect("no entry found for key")
561 }
562}
563
564impl<K, O, S: ?Sized, D> Extend<(K, O::Head)> for HashMapObserver<K, O, S, D>
567where
568 D: Unsigned,
569 S: AsDerefMut<D, Target = HashMap<K, O::Head>>,
570 O: Observer<InnerDepth = Zero>,
571 O::Head: Sized,
572 K: Clone + Eq + Hash,
573{
574 fn extend<I: IntoIterator<Item = (K, O::Head)>>(&mut self, iter: I) {
575 for (key, value) in iter {
576 self.insert(key, value);
577 }
578 }
579}
580
581impl<K: Clone + Eq + Hash, V: Observe> Observe for HashMap<K, V> {
582 type Observer<'ob, S, D>
583 = HashMapObserver<K, V::Observer<'ob, V, Zero>, S, D>
584 where
585 Self: 'ob,
586 D: Unsigned,
587 S: AsDerefMut<D, Target = Self> + ?Sized + 'ob;
588
589 type Spec = DefaultSpec;
590}
591
592default_impl_ref_observe! {
593 impl [K, V] RefObserve for HashMap<K, V>;
594}
595
596impl<K, V> Snapshot for HashMap<K, V>
597where
598 K: Snapshot,
599 K::Snapshot: Eq + Hash,
600 V: Snapshot,
601{
602 type Snapshot = HashMap<K::Snapshot, V::Snapshot>;
603
604 fn to_snapshot(&self) -> Self::Snapshot {
605 self.iter()
606 .map(|(key, value)| (key.to_snapshot(), value.to_snapshot()))
607 .collect()
608 }
609
610 fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
611 self.len() == snapshot.len()
612 && self
613 .iter()
614 .zip(snapshot.iter())
615 .all(|((key_a, value_a), (key_b, value_b))| key_a.eq_snapshot(key_b) && value_a.eq_snapshot(value_b))
616 }
617}
618
619#[cfg(test)]
620mod tests {
621 use std::collections::HashMap;
622
623 use morphix_test_utils::*;
624 use serde_json::json;
625
626 use super::*;
627 use crate::adapter::Json;
628 use crate::observe::{ObserveExt, SerializeObserverExt};
629 use crate::{Mutation, MutationKind};
630
631 #[test]
632 fn remove_nonexistent_key() {
633 let mut map = HashMap::from([("a", "x".to_string())]);
634 let mut ob = map.__observe();
635 assert_eq!(ob.remove("nonexistent"), None);
636 let Json(mutation) = ob.flush().unwrap();
637 assert_eq!(mutation, None);
638 }
639
640 #[test]
641 fn insert_then_remove() {
642 let mut map = HashMap::from([("a", "x".to_string())]);
643 let mut ob = map.__observe();
644 assert_eq!(ob.insert("b", "y".to_string()), None);
645 assert_eq!(ob.remove("b"), Some("y".to_string()));
646 assert_eq!(ob.untracked_ref().len(), 1);
647 assert_eq!(ob.untracked_ref().get("a"), Some(&"x".to_string()));
648 let Json(mutation) = ob.flush().unwrap();
649 assert_eq!(mutation, None);
650 }
651
652 #[test]
653 fn remove_then_insert() {
654 let mut map = HashMap::from([("a", "x".to_string())]);
655 let mut ob = map.__observe();
656 assert_eq!(ob.remove("a"), Some("x".to_string()));
657 assert_eq!(ob.insert("a", "y".to_string()), None);
658 assert_eq!(ob.untracked_ref().get("a"), Some(&"y".to_string()));
659 let Json(mutation) = ob.flush().unwrap();
660 assert_eq!(mutation, Some(replace!(a, json!("y"))));
661 }
662
663 #[test]
664 fn remove_entry() {
665 let mut map = HashMap::from([("a", "x".to_string()), ("b", "y".to_string())]);
666 let mut ob = map.__observe();
667 assert_eq!(ob.remove_entry("a"), Some(("a", "x".to_string())));
668 assert_eq!(ob.untracked_ref().len(), 1);
669 let Json(mutation) = ob.flush().unwrap();
670 assert_eq!(mutation, Some(delete!(a)));
671 }
672
673 #[test]
674 fn retain() {
675 let mut map = HashMap::from([("a", 1i32), ("b", 2), ("c", 3)]);
676 let mut ob = map.__observe();
677 ob.retain(|_, v| *v % 2 != 0);
678 assert_eq!(ob.untracked_ref(), &HashMap::from([("a", 1), ("c", 3)]));
679 let Json(mutation) = ob.flush().unwrap();
680 assert_eq!(mutation, Some(delete!(b)));
681 }
682
683 #[test]
684 fn extend() {
685 let mut map = HashMap::from([("a", "x".to_string())]);
686 let mut ob = map.__observe();
687 ob.extend([("b", "y".to_string()), ("c", "z".to_string())]);
688 assert_eq!(ob.untracked_ref().len(), 3);
689 let Json(mutation) = ob.flush().unwrap();
690 assert!(mutation.is_some());
691 }
692
693 #[test]
694 fn extract_if() {
695 let mut map = HashMap::from([("a", 1i32), ("b", 2), ("c", 3), ("d", 4)]);
696 let mut ob = map.__observe();
697 let extracted: HashMap<_, _> = ob.extract_if(|_, v| *v % 2 == 0).collect();
698 assert_eq!(extracted, HashMap::from([("b", 2), ("d", 4)]));
699 assert_eq!(ob.untracked_ref(), &HashMap::from([("a", 1), ("c", 3)]));
700 let Json(mutation) = ob.flush().unwrap();
701 assert!(mutation.is_some());
702 let mutation = mutation.unwrap();
703 assert!(matches!(mutation.kind, MutationKind::Batch(_)));
704 }
705
706 #[test]
707 fn extract_if_insert_then_extract() {
708 let mut map = HashMap::from([("a", 1i32)]);
709 let mut ob = map.__observe();
710 ob.insert("b", 2);
711 let extracted: HashMap<_, _> = ob.extract_if(|k, _| *k == "b").collect();
713 assert_eq!(extracted, HashMap::from([("b", 2)]));
714 let Json(mutation) = ob.flush().unwrap();
715 assert_eq!(mutation, None);
716 }
717
718 #[test]
719 fn get_mut_then_insert() {
720 let mut map = HashMap::from([("a", "x".to_string())]);
721 let mut ob = map.__observe();
722 ob.get_mut("a").unwrap().push_str(" world");
723 ob.insert("a", "bye".to_string());
724 assert_eq!(ob.untracked_ref().get("a"), Some(&"bye".to_string()));
725 let Json(mutation) = ob.flush().unwrap();
726 assert_eq!(mutation, Some(replace!(a, json!("bye"))));
727 }
728
729 #[test]
730 fn insert_then_get_mut() {
731 let mut map = HashMap::from([("a", "x".to_string())]);
732 let mut ob = map.__observe();
733 ob.insert("b", "hello".to_string());
734 ob.get_mut("b").unwrap().push_str(" world");
735 assert_eq!(ob.untracked_ref().get("b"), Some(&"hello world".to_string()));
736 let Json(mutation) = ob.flush().unwrap();
737 assert_eq!(mutation, Some(replace!(b, json!("hello world"))));
738 }
739
740 #[test]
741 fn iter_mut() {
742 let mut map = HashMap::from([("a", "x".to_string()), ("b", "y".to_string())]);
743 let mut ob = map.__observe();
744 for (_, v) in ob.iter_mut() {
745 v.push_str("!");
746 }
747 assert_eq!(ob.untracked_ref().get("a"), Some(&"x!".to_string()));
748 assert_eq!(ob.untracked_ref().get("b"), Some(&"y!".to_string()));
749 let Json(mutation) = ob.flush().unwrap();
750 assert!(mutation.is_some());
751 let mutation = mutation.unwrap();
752 assert!(matches!(mutation.kind, MutationKind::Batch(_)));
753 if let MutationKind::Batch(batch) = mutation.kind {
754 assert_eq!(batch.len(), 2);
755 for m in &batch {
756 assert_eq!(m.kind, MutationKind::Append(json!("!")));
757 }
758 }
759 }
760
761 #[test]
762 fn values_mut() {
763 let mut map = HashMap::from([("a", "hello".to_string()), ("b", "world".to_string())]);
764 let mut ob = map.__observe();
765 for v in ob.values_mut() {
766 v.push('~');
767 }
768 let Json(mutation) = ob.flush().unwrap();
769 assert!(mutation.is_some());
770 let mutation = mutation.unwrap();
771 assert!(matches!(mutation.kind, MutationKind::Batch(_)));
772 if let MutationKind::Batch(batch) = mutation.kind {
773 assert_eq!(batch.len(), 2);
774 for m in &batch {
775 assert_eq!(m.kind, MutationKind::Append(json!("~")));
776 }
777 }
778 }
779
780 fn sorted_mutations(mutation: Option<Mutation<serde_json::Value>>) -> Vec<Mutation<serde_json::Value>> {
781 let Some(mutation) = mutation else {
782 return vec![];
783 };
784 let mut batch = match mutation.kind {
785 MutationKind::Batch(batch) => batch,
786 _ => vec![mutation],
787 };
788 batch.sort_by(|a, b| a.path.cmp(&b.path));
789 batch
790 }
791
792 #[test]
793 fn flush_flatten_no_change() {
794 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
795 let mut ob = map.__observe();
796 let Json(mutation) = ob.flat_flush().unwrap();
797 assert_eq!(mutation, None);
798 }
799
800 #[test]
801 fn flush_flatten_deref_mut_only() {
802 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
803 let mut ob = map.__observe();
804 **ob = HashMap::from([("a", 10), ("b", 20)]);
805 let Json(mutation) = ob.flat_flush().unwrap();
806 let batch = sorted_mutations(mutation);
807 assert_eq!(batch.len(), 2);
808 assert_eq!(batch[0], replace!(a, json!(10)));
809 assert_eq!(batch[1], replace!(b, json!(20)));
810 }
811
812 #[test]
814 fn flush_flatten_inserted_then_absent() {
815 let mut map = HashMap::from([("a", 1i32)]);
816 let mut ob = map.__observe();
817 ob.insert("b", 2);
818 **ob = HashMap::from([("a", 10)]);
819 let Json(mutation) = ob.flat_flush().unwrap();
820 let batch = sorted_mutations(mutation);
821 assert_eq!(batch.len(), 1);
822 assert_eq!(batch[0], replace!(a, json!(10)));
823 }
824
825 #[test]
827 fn flush_flatten_inserted_then_present() {
828 let mut map = HashMap::from([("a", 1i32)]);
829 let mut ob = map.__observe();
830 ob.insert("b", 2);
831 **ob = HashMap::from([("a", 10), ("b", 20)]);
832 let Json(mutation) = ob.flat_flush().unwrap();
833 let batch = sorted_mutations(mutation);
834 assert_eq!(batch.len(), 2);
835 assert_eq!(batch[0], replace!(a, json!(10)));
836 assert_eq!(batch[1], replace!(b, json!(20)));
837 }
838
839 #[test]
841 fn flush_flatten_deleted_then_absent() {
842 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
843 let mut ob = map.__observe();
844 ob.remove("b");
845 **ob = HashMap::from([("a", 10)]);
846 let Json(mutation) = ob.flat_flush().unwrap();
847 let batch = sorted_mutations(mutation);
848 assert_eq!(batch.len(), 2);
849 assert_eq!(batch[0], replace!(a, json!(10)));
850 assert_eq!(batch[1], delete!(b));
851 }
852
853 #[test]
855 fn flush_flatten_deleted_then_present() {
856 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
857 let mut ob = map.__observe();
858 ob.remove("b");
859 **ob = HashMap::from([("a", 10), ("b", 20)]);
860 let Json(mutation) = ob.flat_flush().unwrap();
861 let batch = sorted_mutations(mutation);
862 assert_eq!(batch.len(), 2);
863 assert_eq!(batch[0], replace!(a, json!(10)));
864 assert_eq!(batch[1], replace!(b, json!(20)));
865 }
866
867 #[test]
869 fn flush_flatten_replaced_then_absent() {
870 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
871 let mut ob = map.__observe();
872 ob.insert("b", 99);
873 **ob = HashMap::from([("a", 10)]);
874 let Json(mutation) = ob.flat_flush().unwrap();
875 let batch = sorted_mutations(mutation);
876 assert_eq!(batch.len(), 2);
877 assert_eq!(batch[0], replace!(a, json!(10)));
878 assert_eq!(batch[1], delete!(b));
879 }
880
881 #[test]
883 fn flush_flatten_replaced_then_present() {
884 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
885 let mut ob = map.__observe();
886 ob.insert("b", 99);
887 **ob = HashMap::from([("a", 10), ("b", 20)]);
888 let Json(mutation) = ob.flat_flush().unwrap();
889 let batch = sorted_mutations(mutation);
890 assert_eq!(batch.len(), 2);
891 assert_eq!(batch[0], replace!(a, json!(10)));
892 assert_eq!(batch[1], replace!(b, json!(20)));
893 }
894
895 #[test]
897 fn flush_flatten_granular() {
898 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
899 let mut ob = map.__observe();
900 ob.insert("a", 10);
901 let Json(mutation) = ob.flat_flush().unwrap();
902 assert_eq!(mutation, Some(replace!(a, json!(10))));
903 }
904
905 #[test]
907 fn flush_flatten_deref_mut_new_keys() {
908 let mut map = HashMap::from([("a", 1i32), ("b", 2)]);
909 let mut ob = map.__observe();
910 **ob = HashMap::from([("c", 30)]);
911 let Json(mutation) = ob.flat_flush().unwrap();
912 let batch = sorted_mutations(mutation);
913 assert_eq!(batch.len(), 3);
914 assert_eq!(batch[0], delete!(a));
915 assert_eq!(batch[1], delete!(b));
916 assert_eq!(batch[2], replace!(c, json!(30)));
917 }
918}