oxigdal_sync/
vector_clock.rs1use crate::{DeviceId, Timestamp, VersionVector};
8use serde::{Deserialize, Serialize};
9use std::cmp::Ordering;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ClockOrdering {
15 Before,
17 After,
19 Equal,
21 Concurrent,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30pub struct VectorClock {
31 clock: VersionVector,
33 device_id: DeviceId,
35}
36
37impl VectorClock {
38 pub fn new(device_id: DeviceId) -> Self {
52 let mut clock = HashMap::new();
53 clock.insert(device_id.clone(), 0);
54
55 Self { clock, device_id }
56 }
57
58 pub fn from_version_vector(device_id: DeviceId, clock: VersionVector) -> Self {
65 Self { clock, device_id }
66 }
67
68 pub fn tick(&mut self) -> Timestamp {
82 let entry = self.clock.entry(self.device_id.clone()).or_insert(0);
83 *entry += 1;
84 *entry
85 }
86
87 pub fn get_time(&self, device_id: &DeviceId) -> Option<Timestamp> {
97 self.clock.get(device_id).copied()
98 }
99
100 pub fn current_time(&self) -> Timestamp {
102 self.clock.get(&self.device_id).copied().unwrap_or(0)
103 }
104
105 pub fn merge(&mut self, other: &VectorClock) {
129 for (device_id, ×tamp) in &other.clock {
130 let entry = self.clock.entry(device_id.clone()).or_insert(0);
131 *entry = (*entry).max(timestamp);
132 }
133 }
134
135 pub fn compare(&self, other: &VectorClock) -> ClockOrdering {
159 let mut less_than = false;
160 let mut greater_than = false;
161
162 let mut all_devices = self.clock.keys().collect::<Vec<_>>();
164 for device in other.clock.keys() {
165 if !all_devices.contains(&device) {
166 all_devices.push(device);
167 }
168 }
169
170 for device_id in all_devices {
172 let self_time = self.clock.get(device_id).copied().unwrap_or(0);
173 let other_time = other.clock.get(device_id).copied().unwrap_or(0);
174
175 match self_time.cmp(&other_time) {
176 Ordering::Less => less_than = true,
177 Ordering::Greater => greater_than = true,
178 Ordering::Equal => {}
179 }
180 }
181
182 match (less_than, greater_than) {
183 (false, false) => ClockOrdering::Equal,
184 (true, false) => ClockOrdering::Before,
185 (false, true) => ClockOrdering::After,
186 (true, true) => ClockOrdering::Concurrent,
187 }
188 }
189
190 pub fn happened_before(&self, other: &VectorClock) -> bool {
192 matches!(self.compare(other), ClockOrdering::Before)
193 }
194
195 pub fn happened_after(&self, other: &VectorClock) -> bool {
197 matches!(self.compare(other), ClockOrdering::After)
198 }
199
200 pub fn is_concurrent(&self, other: &VectorClock) -> bool {
202 matches!(self.compare(other), ClockOrdering::Concurrent)
203 }
204
205 pub fn device_id(&self) -> &DeviceId {
207 &self.device_id
208 }
209
210 pub fn as_version_vector(&self) -> &VersionVector {
212 &self.clock
213 }
214
215 pub fn into_version_vector(self) -> VersionVector {
217 self.clock
218 }
219
220 pub fn with_device_id(&self, device_id: DeviceId) -> Self {
222 Self {
223 clock: self.clock.clone(),
224 device_id,
225 }
226 }
227
228 pub fn update(&mut self, device_id: DeviceId, timestamp: Timestamp) {
235 let entry = self.clock.entry(device_id).or_insert(0);
236 *entry = (*entry).max(timestamp);
237 }
238
239 pub fn sum(&self) -> Timestamp {
241 self.clock.values().sum()
242 }
243
244 pub fn is_empty(&self) -> bool {
246 self.clock.is_empty()
247 }
248
249 pub fn len(&self) -> usize {
251 self.clock.len()
252 }
253
254 pub fn devices(&self) -> Vec<DeviceId> {
256 self.clock.keys().cloned().collect()
257 }
258}
259
260impl Default for VectorClock {
261 fn default() -> Self {
262 Self::new("default".to_string())
263 }
264}
265
266pub trait CausalOrdering {
268 fn precedes(&self, other: &Self) -> bool;
270
271 fn concurrent_with(&self, other: &Self) -> bool;
273}
274
275impl CausalOrdering for VectorClock {
276 fn precedes(&self, other: &Self) -> bool {
277 self.happened_before(other)
278 }
279
280 fn concurrent_with(&self, other: &Self) -> bool {
281 self.is_concurrent(other)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn test_vector_clock_creation() {
291 let clock = VectorClock::new("device-1".to_string());
292 assert_eq!(clock.get_time(&"device-1".to_string()), Some(0));
293 assert_eq!(clock.device_id(), "device-1");
294 }
295
296 #[test]
297 fn test_tick() {
298 let mut clock = VectorClock::new("device-1".to_string());
299 assert_eq!(clock.tick(), 1);
300 assert_eq!(clock.tick(), 2);
301 assert_eq!(clock.get_time(&"device-1".to_string()), Some(2));
302 }
303
304 #[test]
305 fn test_merge() {
306 let mut clock1 = VectorClock::new("device-1".to_string());
307 let mut clock2 = VectorClock::new("device-2".to_string());
308
309 clock1.tick();
310 clock1.tick();
311 clock2.tick();
312
313 clock1.merge(&clock2);
314
315 assert_eq!(clock1.get_time(&"device-1".to_string()), Some(2));
316 assert_eq!(clock1.get_time(&"device-2".to_string()), Some(1));
317 }
318
319 #[test]
320 fn test_compare_equal() {
321 let clock1 = VectorClock::new("device-1".to_string());
322 let clock2 = VectorClock::new("device-1".to_string());
323
324 assert_eq!(clock1.compare(&clock2), ClockOrdering::Equal);
325 }
326
327 #[test]
328 fn test_compare_before() {
329 let clock1 = VectorClock::new("device-1".to_string());
330 let mut clock2 = VectorClock::new("device-1".to_string());
331
332 clock2.tick();
333
334 assert_eq!(clock1.compare(&clock2), ClockOrdering::Before);
335 assert!(clock1.happened_before(&clock2));
336 }
337
338 #[test]
339 fn test_compare_after() {
340 let mut clock1 = VectorClock::new("device-1".to_string());
341 let clock2 = VectorClock::new("device-1".to_string());
342
343 clock1.tick();
344
345 assert_eq!(clock1.compare(&clock2), ClockOrdering::After);
346 assert!(clock1.happened_after(&clock2));
347 }
348
349 #[test]
350 fn test_compare_concurrent() {
351 let mut clock1 = VectorClock::new("device-1".to_string());
352 let mut clock2 = VectorClock::new("device-2".to_string());
353
354 clock1.tick();
355 clock2.tick();
356
357 assert_eq!(clock1.compare(&clock2), ClockOrdering::Concurrent);
358 assert!(clock1.is_concurrent(&clock2));
359 }
360
361 #[test]
362 fn test_complex_merge() {
363 let mut clock1 = VectorClock::new("device-1".to_string());
364 let mut clock2 = VectorClock::new("device-2".to_string());
365 let mut clock3 = VectorClock::new("device-3".to_string());
366
367 clock1.tick();
368 clock1.tick();
369
370 clock2.tick();
371 clock2.merge(&clock1);
372 clock2.tick();
373
374 clock3.tick();
375
376 clock1.merge(&clock2);
377 clock1.merge(&clock3);
378
379 assert_eq!(clock1.get_time(&"device-1".to_string()), Some(2));
380 assert_eq!(clock1.get_time(&"device-2".to_string()), Some(2));
381 assert_eq!(clock1.get_time(&"device-3".to_string()), Some(1));
382 }
383}