Skip to main content

ucm_core/
version.rs

1//! Version tracking for optimistic concurrency control.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// Block version for optimistic concurrency control
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Version {
9    /// Monotonically increasing counter
10    pub counter: u64,
11    /// Timestamp of last modification
12    pub timestamp: DateTime<Utc>,
13}
14
15impl Version {
16    /// Create an initial version
17    pub fn initial() -> Self {
18        Self {
19            counter: 1,
20            timestamp: Utc::now(),
21        }
22    }
23
24    /// Increment the version
25    pub fn increment(&mut self) {
26        self.counter += 1;
27        self.timestamp = Utc::now();
28    }
29
30    /// Create the next version
31    pub fn next(&self) -> Self {
32        Self {
33            counter: self.counter + 1,
34            timestamp: Utc::now(),
35        }
36    }
37
38    /// Check if this version is newer than another
39    pub fn is_newer_than(&self, other: &Version) -> bool {
40        self.counter > other.counter
41    }
42}
43
44impl Default for Version {
45    fn default() -> Self {
46        Self::initial()
47    }
48}
49
50impl std::fmt::Display for Version {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(f, "v{}", self.counter)
53    }
54}
55
56/// Document version with additional metadata
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58pub struct DocumentVersion {
59    /// Version counter
60    pub counter: u64,
61    /// Timestamp
62    pub timestamp: DateTime<Utc>,
63    /// Hash of document state (for integrity checking)
64    pub state_hash: [u8; 8],
65}
66
67impl DocumentVersion {
68    /// Create initial document version
69    pub fn initial() -> Self {
70        Self {
71            counter: 1,
72            timestamp: Utc::now(),
73            state_hash: [0u8; 8],
74        }
75    }
76
77    /// Increment version with new state hash
78    pub fn increment(&mut self, state_hash: [u8; 8]) {
79        self.counter += 1;
80        self.timestamp = Utc::now();
81        self.state_hash = state_hash;
82    }
83
84    /// Check if versions match
85    pub fn matches(&self, other: &DocumentVersion) -> bool {
86        self.counter == other.counter && self.state_hash == other.state_hash
87    }
88}
89
90impl Default for DocumentVersion {
91    fn default() -> Self {
92        Self::initial()
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_version_increment() {
102        let mut v = Version::initial();
103        assert_eq!(v.counter, 1);
104
105        v.increment();
106        assert_eq!(v.counter, 2);
107    }
108
109    #[test]
110    fn test_version_comparison() {
111        let v1 = Version::initial();
112        let v2 = v1.next();
113
114        assert!(v2.is_newer_than(&v1));
115        assert!(!v1.is_newer_than(&v2));
116    }
117
118    #[test]
119    fn test_document_version() {
120        let mut dv = DocumentVersion::initial();
121        let hash = [1u8; 8];
122        dv.increment(hash);
123
124        assert_eq!(dv.counter, 2);
125        assert_eq!(dv.state_hash, hash);
126    }
127}