1use crate::CrdtMerge;
5use fxhash::FxHashMap;
6use serde::{Deserialize, Serialize};
7use std::cmp::Ordering;
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
13pub struct VectorClock {
14 pub clocks: FxHashMap<String, u64>,
15}
16
17impl VectorClock {
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn increment(&mut self, actor: &str) {
24 *self.clocks.entry(actor.to_string()).or_insert(0) += 1;
25 }
26
27 pub fn get(&self, actor: &str) -> u64 {
29 *self.clocks.get(actor).unwrap_or(&0)
30 }
31
32 pub fn merge_clock(&mut self, other: &VectorClock) {
34 for (actor, &count) in &other.clocks {
35 let entry = self.clocks.entry(actor.clone()).or_insert(0);
36 *entry = std::cmp::max(*entry, count);
37 }
38 }
39
40 pub fn happened_before(&self, other: &VectorClock) -> bool {
43 let mut strictly_less = false;
44
45 for (actor, &count) in &self.clocks {
47 let other_count = other.get(actor);
48 if count > other_count {
49 return false;
50 }
51 if count < other_count {
52 strictly_less = true;
53 }
54 }
55
56 if !strictly_less {
58 for (actor, &count) in &other.clocks {
59 if !self.clocks.contains_key(actor) && count > 0 {
60 strictly_less = true;
61 break;
62 }
63 }
64 }
65
66 strictly_less
67 }
68
69 pub fn is_concurrent(&self, other: &VectorClock) -> bool {
71 !self.happened_before(other) && !other.happened_before(self) && self != other
72 }
73
74 pub fn causal_cmp(&self, other: &VectorClock) -> Option<Ordering> {
81 if self == other {
82 Some(Ordering::Equal)
83 } else if self.happened_before(other) {
84 Some(Ordering::Less)
85 } else if other.happened_before(self) {
86 Some(Ordering::Greater)
87 } else {
88 None }
90 }
91}
92
93impl CrdtMerge for VectorClock {
94 fn merge(&mut self, other: &Self) {
95 self.merge_clock(other);
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_vector_clock_ordering() {
105 let mut a = VectorClock::new();
106 a.increment("node1"); let mut b = a.clone();
109 b.increment("node1"); assert!(a.happened_before(&b));
113 assert!(!b.happened_before(&a));
114 assert_eq!(a.causal_cmp(&b), Some(Ordering::Less));
115
116 let mut c = a.clone();
117 c.increment("node2"); assert!(!b.happened_before(&c));
123 assert!(!c.happened_before(&b));
124 assert!(b.is_concurrent(&c));
125 assert_eq!(b.causal_cmp(&c), None);
126 }
127
128 #[test]
129 fn test_merge() {
130 let mut a = VectorClock::new();
131 a.increment("node1"); let mut b = VectorClock::new();
134 b.increment("node2"); a.merge(&b); assert_eq!(a.get("node1"), 1);
138 assert_eq!(a.get("node2"), 1);
139 }
140}