1use uuid::Uuid;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct Version {
6 id: Uuid,
7 counter: usize,
8}
9
10pub const SENTINEL_VERSION: Version = Version::sentinel();
12
13impl Version {
14 #[inline]
20 #[must_use]
21 pub const fn sentinel() -> Self {
22 Self {
23 id: Uuid::from_bytes([0xFF; 16]),
24 counter: usize::MAX,
25 }
26 }
27
28 #[inline]
30 #[must_use]
31 pub fn new() -> Self {
32 Self {
33 id: Uuid::new_v4(),
34 counter: 0,
35 }
36 }
37
38 #[inline]
40 pub fn reset(&mut self) {
41 self.id = Uuid::new_v4();
42 self.counter = 0;
43 }
44
45 #[inline]
50 pub fn increment(&mut self) {
51 self.counter = self.counter.wrapping_add(1);
52 if self.counter == 0 {
53 self.id = Uuid::new_v4();
54 }
55 }
56
57 #[inline]
62 pub fn increment_wrap(&mut self) {
63 self.counter = self.counter.wrapping_add(1);
64 }
65
66 #[inline]
72 #[must_use]
73 pub fn alike(&self, other: &Self) -> bool {
74 self.id == other.id
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn sentinel() {
84 let version = Version::sentinel();
85 assert_eq!(version.id.as_u128(), u128::MAX);
86 assert_eq!(version.counter, usize::MAX);
87 }
88
89 #[test]
90 fn new() {
91 let version = Version::new();
92 assert!(version.id.as_u128() > 0);
93 assert_eq!(version.counter, 0);
94 }
95
96 #[test]
97 fn reset() {
98 let mut version = Version::new();
99 version.counter = 42;
100 let prev_id = version.id;
101 version.reset();
102 assert_ne!(version.id, prev_id);
103 assert_eq!(version.counter, 0);
104 }
105
106 #[test]
107 fn increment() {
108 let mut version = Version::new();
109 let prev_id = version.id;
110 version.increment();
111 assert_eq!(version.id, prev_id);
112 assert_eq!(version.counter, 1);
113 }
114
115 #[test]
116 fn increment_with_wrap() {
117 let mut version = Version::new();
118 version.counter = usize::MAX;
119 let prev_id = version.id;
120 version.increment();
121 assert_ne!(version.id, prev_id);
122 assert_eq!(version.counter, 0);
123 }
124
125 #[test]
126 fn increment_wrap() {
127 let mut version = Version::new();
128 let prev_id = version.id;
129 version.increment_wrap();
130 assert_eq!(version.id, prev_id);
131 assert_eq!(version.counter, 1);
132 }
133
134 #[test]
135 fn increment_wrap_with_wrap() {
136 let mut version = Version::new();
137 version.counter = usize::MAX;
138 let prev_id = version.id;
139 version.increment_wrap();
140 assert_eq!(version.id, prev_id);
141 assert_eq!(version.counter, 0);
142 }
143
144 #[test]
145 fn alike_match() {
146 let version = Version::new();
147 let other = version;
148 assert!(other.alike(&version));
149 }
150
151 #[test]
152 fn alike_mismatch() {
153 let version = Version::new();
154 let other = Version::new();
155 assert!(!other.alike(&version));
156 }
157}