1//! Whether the child has put a fact away, kept apart from the parents' permanent `forgotten`. 2//! 3//! The two are different acts with different reaches. **Forgetting** is the parents': the fact is 4//! deleted and its identity is tombstoned so no device brings it back. **Hiding** is the child's: the 5//! fact stays (the parents still see it, under "removed by her"), Whiskers stops using it, and a 6//! parent can restore it. A hidden fact is therefore not a second list but a state of the fact. 7//! 8//! The state is a last-writer-wins register, so merging two copies in any order, any number of times, 9//! gives the same answer (the invariant of `MemorySnapshot`). It carries its own time, `at_ms`, and the 10//! newer write wins; on an exact tie the fact stays hidden, so the answer does not depend on which copy 11//! was merged first and a tie never lets Whiskers use what she put away. 12//! 13//! The state is a typed enum, not two booleans: "hidden and shown" and "hidden with no time" cannot be 14//! written down. 15 16use serde::{Deserialize, Serialize}; 17 18/// Whether Whiskers may use a fact, and the moment that was decided. 19#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 20pub enum Visibility { 21 /// Whiskers uses it. `at_ms` is when a parent last restored it (0 for a fact never hidden). 22 Shown { at_ms: u64 }, 23 /// She put it away. Whiskers does not use it; the parents can restore it. 24 HiddenByChild { at_ms: u64 }, 25} 26 27impl Default for Visibility { 28 fn default() -> Self { 29 Visibility::Shown { at_ms: 0 } 30 } 31} 32 33impl Visibility { 34 /// True for the state every new fact has, which is left out of the stored and wire forms so a 35 /// fact nobody has touched is byte for byte what it was before this state existed. 36 pub fn is_default(&self) -> bool { 37 *self == Visibility::default() 38 } 39 40 pub fn is_hidden(&self) -> bool { 41 matches!(self, Visibility::HiddenByChild { .. }) 42 } 43 44 pub fn at_ms(&self) -> u64 { 45 match *self { 46 Visibility::Shown { at_ms } | Visibility::HiddenByChild { at_ms } => at_ms, 47 } 48 } 49 50 /// Her putting the fact away at `now_ms`. The write is made later than the one it follows even if 51 /// this device's clock is behind, so a causally later act always wins the merge. 52 pub fn hidden_after(self, now_ms: u64) -> Visibility { 53 Visibility::HiddenByChild { at_ms: now_ms.max(self.at_ms().saturating_add(1)) } 54 } 55 56 /// A parent's restore at `now_ms`, later than whatever it follows (see [`hidden_after`](Self::hidden_after)). 57 pub fn restored_after(self, now_ms: u64) -> Visibility { 58 Visibility::Shown { at_ms: now_ms.max(self.at_ms().saturating_add(1)) } 59 } 60 61 /// The register's merge: the later write, and on a tie the hidden one. Commutative, associative 62 /// and idempotent. 63 pub fn merged(self, other: Visibility) -> Visibility { 64 if other.order_key() > self.order_key() { other } else { self } 65 } 66 67 fn order_key(&self) -> (u64, bool) { 68 (self.at_ms(), self.is_hidden()) 69 } 70} 71 72#[cfg(test)] 73mod tests { 74 use super::*; 75 76 fn all() -> Vec<Visibility> { 77 let mut v = Vec::new(); 78 for t in [0, 1, 2, 5] { 79 v.push(Visibility::Shown { at_ms: t }); 80 v.push(Visibility::HiddenByChild { at_ms: t }); 81 } 82 v 83 } 84 85 #[test] 86 fn the_merge_is_commutative_associative_and_idempotent() { 87 for a in all() { 88 assert_eq!(a.merged(a), a); 89 for b in all() { 90 assert_eq!(a.merged(b), b.merged(a), "{a:?} {b:?}"); 91 for c in all() { 92 assert_eq!(a.merged(b).merged(c), a.merged(b.merged(c)), "{a:?} {b:?} {c:?}"); 93 } 94 } 95 } 96 } 97 98 #[test] 99 fn a_tie_stays_hidden_in_either_order() { 100 let (s, h) = (Visibility::Shown { at_ms: 7 }, Visibility::HiddenByChild { at_ms: 7 }); 101 assert_eq!(s.merged(h), h); 102 assert_eq!(h.merged(s), h); 103 } 104 105 #[test] 106 fn a_restore_beats_the_hide_it_follows_even_from_a_slow_clock() { 107 let hidden = Visibility::default().hidden_after(1_000); 108 let restored = hidden.restored_after(10); // the parents' clock is behind 109 assert!(!restored.is_hidden()); 110 assert_eq!(hidden.merged(restored), restored); 111 assert_eq!(restored.merged(hidden), restored); 112 // and her hiding it again beats that restore 113 let again = restored.hidden_after(0); 114 assert_eq!(restored.merged(again), again); 115 } 116 117 #[test] 118 fn the_default_is_left_out_of_the_stored_form() { 119 assert!(Visibility::default().is_default()); 120 assert!(!Visibility::default().hidden_after(3).is_default()); 121 assert!(!Visibility::default().hidden_after(3).restored_after(9).is_default()); 122 } 123}