automerge/
clock.rs

1use crate::types::OpId;
2
3use std::num::NonZeroU32;
4
5#[derive(Default, Debug, Clone, PartialEq)]
6pub(crate) struct Clock(pub(crate) Vec<u32>);
7
8#[derive(Default, Debug, Clone, PartialEq)]
9pub(crate) struct SeqClock(pub(crate) Vec<Option<NonZeroU32>>);
10
11impl SeqClock {
12    pub(crate) fn iter(&self) -> impl Iterator<Item = (usize, Option<NonZeroU32>)> + '_ {
13        self.0.iter().copied().enumerate()
14    }
15
16    pub(crate) fn remove_actor(&mut self, idx: usize) {
17        self.0.remove(idx);
18    }
19
20    pub(crate) fn rewrite_with_new_actor(&mut self, idx: usize) {
21        self.0.insert(idx, None)
22    }
23
24    pub(crate) fn get_for_actor(&self, actor_index: &usize) -> Option<NonZeroU32> {
25        self.0.get(*actor_index).copied().flatten()
26    }
27
28    pub(crate) fn new(size: usize) -> Self {
29        Self(vec![None; size])
30    }
31
32    pub(crate) fn include(&mut self, actor_idx: usize, data: Option<u32>) -> bool {
33        if let Some(data) = data {
34            match self.0[actor_idx] {
35                None => {
36                    self.0[actor_idx] = NonZeroU32::try_from(data).ok();
37                    true
38                }
39                Some(old_data) if old_data.get() < data => {
40                    self.0[actor_idx] = NonZeroU32::try_from(data).ok();
41                    true
42                }
43                _ => false,
44            }
45        } else {
46            false
47        }
48    }
49
50    pub(crate) fn merge(a: &mut Self, b: &Self) {
51        for (a, b) in std::iter::zip(a.0.iter_mut(), b.0.iter()) {
52            if *a < *b {
53                *a = *b;
54            }
55        }
56    }
57}
58
59#[derive(Debug, Clone, PartialEq)]
60pub(crate) enum ClockRange {
61    Current(Option<Clock>),
62    Diff(Clock, Clock),
63}
64
65impl Default for ClockRange {
66    fn default() -> Self {
67        Self::Current(None)
68    }
69}
70
71impl ClockRange {
72    pub(crate) fn current(clock: Option<Clock>) -> Self {
73        Self::Current(clock)
74    }
75
76    pub(crate) fn after(&self) -> Option<&Clock> {
77        match self {
78            Self::Diff(_, after) => Some(after),
79            Self::Current(Some(after)) => Some(after),
80            _ => None,
81        }
82    }
83
84    pub(crate) fn visible_after(&self, id: &OpId) -> bool {
85        match self {
86            Self::Current(Some(after)) => after.covers(id),
87            Self::Diff(_, after) => after.covers(id),
88            _ => true,
89        }
90    }
91
92    pub(crate) fn visible_before(&self, id: &OpId) -> bool {
93        self.predates(id)
94    }
95
96    pub(crate) fn predates(&self, id: &OpId) -> bool {
97        match self {
98            Self::Diff(before, _) => before.covers(id),
99            _ => false,
100        }
101    }
102}
103
104impl Clock {
105    pub(crate) fn isolate(&mut self, actor_index: usize) {
106        self.0[actor_index] = u32::MAX
107    }
108
109    pub(crate) fn covers(&self, id: &OpId) -> bool {
110        self.0[id.actor()] as u64 >= id.counter()
111    }
112}
113
114impl std::iter::FromIterator<Option<u32>> for Clock {
115    fn from_iter<I: IntoIterator<Item = Option<u32>>>(iter: I) -> Self {
116        Clock(iter.into_iter().map(|i| i.unwrap_or(0)).collect())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use std::cmp::Ordering;
124
125    impl Clock {
126        pub(crate) fn new(size: usize) -> Self {
127            Self(vec![0; size])
128        }
129
130        pub(crate) fn include(&mut self, actor_idx: usize, data: u32) -> bool {
131            if data > self.0[actor_idx] {
132                self.0[actor_idx] = data;
133                true
134            } else {
135                false
136            }
137        }
138
139        fn is_greater(&self, other: &Self) -> bool {
140            !std::iter::zip(self.0.iter(), other.0.iter()).any(|(a, b)| a < b)
141        }
142    }
143
144    impl PartialOrd for Clock {
145        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
146            if self.0 == other.0 {
147                Some(Ordering::Equal)
148            } else if self.is_greater(other) {
149                Some(Ordering::Greater)
150            } else if other.is_greater(self) {
151                Some(Ordering::Less)
152            } else {
153                None
154            }
155        }
156    }
157
158    #[test]
159    fn covers() {
160        let mut clock = Clock::new(4);
161
162        clock.include(1, 20);
163        clock.include(2, 10);
164
165        assert!(clock.covers(&OpId::new(10, 1)));
166        assert!(clock.covers(&OpId::new(20, 1)));
167        assert!(!clock.covers(&OpId::new(30, 1)));
168
169        assert!(clock.covers(&OpId::new(5, 2)));
170        assert!(clock.covers(&OpId::new(10, 2)));
171        assert!(!clock.covers(&OpId::new(15, 2)));
172
173        assert!(!clock.covers(&OpId::new(1, 3)));
174        assert!(!clock.covers(&OpId::new(100, 3)));
175    }
176
177    #[test]
178    fn comparison() {
179        let mut base_clock = Clock::new(4);
180        base_clock.include(1, 1);
181        base_clock.include(2, 1);
182
183        let mut after_clock = base_clock.clone();
184        after_clock.include(1, 2);
185
186        assert!(after_clock > base_clock);
187        assert!(base_clock < after_clock);
188
189        assert!(base_clock == base_clock);
190
191        let mut new_actor_clock = base_clock.clone();
192        new_actor_clock.include(3, 1);
193
194        assert_eq!(
195            base_clock.partial_cmp(&new_actor_clock),
196            Some(Ordering::Less)
197        );
198        assert_eq!(
199            new_actor_clock.partial_cmp(&base_clock),
200            Some(Ordering::Greater)
201        );
202
203        assert_eq!(after_clock.partial_cmp(&new_actor_clock), None);
204        assert_eq!(new_actor_clock.partial_cmp(&after_clock), None);
205    }
206}