Skip to main content

oxihuman_core/
clock_version_vector.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5use std::collections::HashMap;
6
7/// A distributed version vector (vector clock).
8pub struct ClockVersionVector {
9    pub clocks: HashMap<String, u64>,
10}
11
12impl ClockVersionVector {
13    pub fn new() -> Self {
14        ClockVersionVector {
15            clocks: HashMap::new(),
16        }
17    }
18}
19
20impl Default for ClockVersionVector {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26pub fn new_clock_version_vector() -> ClockVersionVector {
27    ClockVersionVector::new()
28}
29
30pub fn cvv_increment(v: &mut ClockVersionVector, node: &str) {
31    let counter = v.clocks.entry(node.to_string()).or_insert(0);
32    *counter += 1;
33}
34
35pub fn cvv_get(v: &ClockVersionVector, node: &str) -> u64 {
36    *v.clocks.get(node).unwrap_or(&0)
37}
38
39pub fn cvv_merge(a: &ClockVersionVector, b: &ClockVersionVector) -> ClockVersionVector {
40    let mut merged = ClockVersionVector::new();
41    for (k, &va) in &a.clocks {
42        let vb = *b.clocks.get(k).unwrap_or(&0);
43        merged.clocks.insert(k.clone(), va.max(vb));
44    }
45    for (k, &vb) in &b.clocks {
46        if !merged.clocks.contains_key(k) {
47            merged.clocks.insert(k.clone(), vb);
48        }
49    }
50    merged
51}
52
53/// Returns true if `a` dominates (happens-after or equals) `b`.
54pub fn cvv_dominates(a: &ClockVersionVector, b: &ClockVersionVector) -> bool {
55    for (k, &vb) in &b.clocks {
56        if cvv_get(a, k) < vb {
57            return false;
58        }
59    }
60    true
61}
62
63pub fn cvv_concurrent(a: &ClockVersionVector, b: &ClockVersionVector) -> bool {
64    !cvv_dominates(a, b) && !cvv_dominates(b, a)
65}
66
67pub fn cvv_node_count(v: &ClockVersionVector) -> usize {
68    v.clocks.len()
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_new_empty() {
77        /* new vector has no nodes */
78        let v = new_clock_version_vector();
79        assert_eq!(cvv_node_count(&v), 0);
80    }
81
82    #[test]
83    fn test_increment_and_get() {
84        /* increment raises counter for node */
85        let mut v = new_clock_version_vector();
86        cvv_increment(&mut v, "A");
87        cvv_increment(&mut v, "A");
88        assert_eq!(cvv_get(&v, "A"), 2);
89    }
90
91    #[test]
92    fn test_get_unknown() {
93        /* get for unknown node returns 0 */
94        let v = new_clock_version_vector();
95        assert_eq!(cvv_get(&v, "X"), 0);
96    }
97
98    #[test]
99    fn test_merge() {
100        /* merge takes element-wise max */
101        let mut a = new_clock_version_vector();
102        let mut b = new_clock_version_vector();
103        cvv_increment(&mut a, "A");
104        cvv_increment(&mut a, "A");
105        cvv_increment(&mut b, "A");
106        cvv_increment(&mut b, "B");
107        let m = cvv_merge(&a, &b);
108        assert_eq!(cvv_get(&m, "A"), 2);
109        assert_eq!(cvv_get(&m, "B"), 1);
110    }
111
112    #[test]
113    fn test_dominates() {
114        /* strictly advanced vector dominates the other */
115        let mut a = new_clock_version_vector();
116        let mut b = new_clock_version_vector();
117        cvv_increment(&mut a, "A");
118        cvv_increment(&mut a, "A");
119        cvv_increment(&mut b, "A");
120        assert!(cvv_dominates(&a, &b));
121        assert!(!cvv_dominates(&b, &a));
122    }
123
124    #[test]
125    fn test_concurrent() {
126        /* concurrent when neither dominates */
127        let mut a = new_clock_version_vector();
128        let mut b = new_clock_version_vector();
129        cvv_increment(&mut a, "A");
130        cvv_increment(&mut b, "B");
131        assert!(cvv_concurrent(&a, &b));
132    }
133
134    #[test]
135    fn test_node_count() {
136        /* node count reflects unique nodes */
137        let mut v = new_clock_version_vector();
138        cvv_increment(&mut v, "X");
139        cvv_increment(&mut v, "Y");
140        cvv_increment(&mut v, "X");
141        assert_eq!(cvv_node_count(&v), 2);
142    }
143
144    #[test]
145    fn test_default() {
146        /* Default impl works */
147        let v = ClockVersionVector::default();
148        assert_eq!(v.clocks.len(), 0);
149    }
150}