1use std::collections::HashMap;
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
18pub struct VectorClock {
19 clock: HashMap<String, u64>,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum ClockOrder {
25 Before,
27 After,
29 Concurrent,
31 Equal,
33}
34
35impl VectorClock {
36 pub fn new() -> Self { Self::default() }
38
39 pub fn tick(&mut self, node: impl Into<String>) {
44 let n = node.into();
45 *self.clock.entry(n).or_insert(0) += 1;
46 }
47
48 pub fn get(&self, node: &str) -> u64 {
53 *self.clock.get(node).unwrap_or(&0)
54 }
55
56 pub fn merge(&self, other: &VectorClock) -> VectorClock {
63 let mut result = self.clock.clone();
64 for (node, &ts) in &other.clock {
65 let entry = result.entry(node.clone()).or_insert(0);
66 if ts > *entry { *entry = ts; }
67 }
68 VectorClock { clock: result }
69 }
70
71 pub fn compare(&self, other: &VectorClock) -> ClockOrder {
76 let self_nodes: std::collections::HashSet<&str> =
77 self.clock.keys().map(|s| s.as_str()).collect();
78 let other_nodes: std::collections::HashSet<&str> =
79 other.clock.keys().map(|s| s.as_str()).collect();
80 let all_nodes: std::collections::HashSet<&str> =
81 self_nodes.union(&other_nodes).copied().collect();
82
83 let mut self_less = false;
84 let mut other_less = false;
85
86 for node in all_nodes {
87 let s = self.get(node);
88 let o = other.get(node);
89 if s < o { self_less = true; }
90 if s > o { other_less = true; }
91 }
92
93 match (self_less, other_less) {
94 (false, false) => ClockOrder::Equal,
95 (true, false) => ClockOrder::Before,
96 (false, true) => ClockOrder::After,
97 (true, true) => ClockOrder::Concurrent,
98 }
99 }
100
101 pub fn node_count(&self) -> usize { self.clock.len() }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_vclock_tick_increments_counter() {
111 let mut c = VectorClock::new();
112 c.tick("a");
113 c.tick("a");
114 assert_eq!(c.get("a"), 2);
115 }
116
117 #[test]
118 fn test_vclock_get_unknown_node_returns_zero() {
119 let c = VectorClock::new();
120 assert_eq!(c.get("nobody"), 0);
121 }
122
123 #[test]
124 fn test_vclock_merge_takes_max_component() {
125 let mut c1 = VectorClock::new();
126 c1.tick("a"); c1.tick("a"); let mut c2 = VectorClock::new();
128 c2.tick("a"); c2.tick("b"); let merged = c1.merge(&c2);
130 assert_eq!(merged.get("a"), 2);
131 assert_eq!(merged.get("b"), 1);
132 }
133
134 #[test]
135 fn test_vclock_merge_is_commutative() {
136 let mut c1 = VectorClock::new();
137 c1.tick("x"); c1.tick("x");
138 let mut c2 = VectorClock::new();
139 c2.tick("y");
140 let m1 = c1.merge(&c2);
141 let m2 = c2.merge(&c1);
142 assert_eq!(m1, m2);
143 }
144
145 #[test]
146 fn test_vclock_merge_is_idempotent() {
147 let mut c = VectorClock::new();
148 c.tick("a");
149 let m = c.merge(&c.clone());
150 assert_eq!(m, c);
151 }
152
153 #[test]
154 fn test_vclock_merge_is_associative() {
155 let mut a = VectorClock::new(); a.tick("a");
156 let mut b = VectorClock::new(); b.tick("b");
157 let mut c = VectorClock::new(); c.tick("c");
158 let lhs = a.merge(&b).merge(&c);
159 let rhs = a.merge(&b.merge(&c));
160 assert_eq!(lhs, rhs);
161 }
162
163 #[test]
164 fn test_vclock_compare_before() {
165 let c1 = VectorClock::new();
166 let mut c2 = VectorClock::new();
167 c2.tick("a");
168 assert_eq!(c1.compare(&c2), ClockOrder::Before);
169 }
170
171 #[test]
172 fn test_vclock_compare_after() {
173 let mut c1 = VectorClock::new();
174 c1.tick("a");
175 let c2 = VectorClock::new();
176 assert_eq!(c1.compare(&c2), ClockOrder::After);
177 }
178
179 #[test]
180 fn test_vclock_compare_concurrent() {
181 let mut c1 = VectorClock::new();
182 c1.tick("a");
183 let mut c2 = VectorClock::new();
184 c2.tick("b");
185 assert_eq!(c1.compare(&c2), ClockOrder::Concurrent);
186 }
187
188 #[test]
189 fn test_vclock_compare_equal_empty() {
190 let c1 = VectorClock::new();
191 let c2 = VectorClock::new();
192 assert_eq!(c1.compare(&c2), ClockOrder::Equal);
193 }
194
195 #[test]
196 fn test_vclock_compare_equal_nonempty() {
197 let mut c1 = VectorClock::new();
198 c1.tick("x"); c1.tick("y");
199 let c2 = c1.clone();
200 assert_eq!(c1.compare(&c2), ClockOrder::Equal);
201 }
202
203 #[test]
204 fn test_vclock_node_count() {
205 let mut c = VectorClock::new();
206 c.tick("a"); c.tick("b");
207 assert_eq!(c.node_count(), 2);
208 }
209}