1pub use std::{error, fmt, mem};
7
8use revision::Revisioned;
9
10#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd)]
22pub struct VersionStamp([u8; 10]);
23
24impl serde::Serialize for VersionStamp {
25 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: serde::Serializer,
28 {
29 self.0.serialize(serializer)
30 }
31}
32
33impl<'de> serde::Deserialize<'de> for VersionStamp {
34 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35 where
36 D: serde::Deserializer<'de>,
37 {
38 let res = <[u8; 10]>::deserialize(deserializer)?;
39 Ok(VersionStamp(res))
40 }
41}
42
43impl Revisioned for VersionStamp {
46 fn revision() -> u16 {
47 0
48 }
49
50 fn serialize_revisioned<W: std::io::Write>(&self, w: &mut W) -> Result<(), revision::Error> {
51 self.0.serialize_revisioned(w)
52 }
53
54 fn deserialize_revisioned<R: std::io::Read>(r: &mut R) -> Result<Self, revision::Error>
55 where
56 Self: Sized,
57 {
58 Revisioned::deserialize_revisioned(r).map(VersionStamp)
59 }
60}
61
62impl Default for VersionStamp {
63 fn default() -> Self {
64 VersionStamp::ZERO
65 }
66}
67
68pub struct VersionStampError(());
69
70impl fmt::Display for VersionStampError {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 write!(f, "Invalid version stamp conversion")
73 }
74}
75impl fmt::Debug for VersionStampError {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 fmt::Display::fmt(self, f)
78 }
79}
80impl error::Error for VersionStampError {}
81
82impl VersionStamp {
83 pub const ZERO: VersionStamp = VersionStamp([0; 10]);
84
85 pub const fn from_u64(v: u64) -> Self {
86 let b = v.to_be_bytes();
87 VersionStamp([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], 0, 0])
88 }
89
90 pub const fn from_u64_u16(v: u64, v2: u16) -> Self {
91 let b1 = v.to_be_bytes();
92 let b2 = v2.to_be_bytes();
93 VersionStamp([b1[0], b1[1], b1[2], b1[3], b1[4], b1[5], b1[6], b1[7], b2[0], b2[1]])
94 }
95
96 pub const fn try_from_u128(v: u128) -> Result<Self, VersionStampError> {
97 if (v >> 80) > 0 {
98 return Err(VersionStampError(()));
99 }
100 let b = v.to_be_bytes();
101 Ok(VersionStamp([b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]))
102 }
103
104 pub const fn into_u64_u16(self) -> (u64, u16) {
106 let b = self.0;
107 (
108 u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
109 u16::from_be_bytes([b[8], b[9]]),
110 )
111 }
112
113 pub const fn into_u64_lossy(self) -> u64 {
115 let b = self.0;
116 u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
117 }
118
119 pub const fn try_into_u64(self) -> Result<u64, VersionStampError> {
120 if self.0[8] > 0 || self.0[9] > 0 {
121 return Err(VersionStampError(()));
122 }
123 Ok(self.into_u64_lossy())
124 }
125
126 pub const fn into_u128(self) -> u128 {
127 let b = self.0;
128 u128::from_be_bytes([
129 0, 0, 0, 0, 0, 0, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9],
130 ])
131 }
132
133 pub const fn as_bytes(self) -> [u8; 10] {
134 self.0
135 }
136
137 pub const fn from_bytes(bytes: [u8; 10]) -> Self {
138 Self(bytes)
139 }
140
141 pub const fn from_slice(slice: &[u8]) -> Result<Self, VersionStampError> {
142 if slice.len() != 10 {
143 return Err(VersionStampError(()));
144 }
145 Ok(VersionStamp([
146 slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
147 slice[8], slice[9],
148 ]))
149 }
150
151 pub fn next(self) -> Option<Self> {
152 let (v, suffix) = self.into_u64_u16();
153 let v = v.checked_add(1)?;
154 let next = VersionStamp::from_u64_u16(v, suffix);
155 Some(next)
156 }
157
158 pub fn iter(self) -> VersionStampIter {
160 VersionStampIter {
161 cur: Some(self),
162 }
163 }
164}
165
166pub struct VersionStampIter {
167 cur: Option<VersionStamp>,
168}
169
170impl Iterator for VersionStampIter {
171 type Item = VersionStamp;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 let next = self.cur?.next();
175 mem::replace(&mut self.cur, next)
176 }
177}
178
179#[cfg(test)]
180mod test {
181 use super::VersionStamp;
182
183 #[test]
184 pub fn generate_one_vs() {
185 let vs = VersionStamp::ZERO.iter().take(1).collect::<Vec<_>>();
186 assert_eq!(vs.len(), 1, "Should be 1, but was {:?}", vs);
187 assert_eq!(vs[0], VersionStamp::ZERO);
188 }
189
190 #[test]
191 pub fn generate_two_vs_in_sequence() {
192 let vs = VersionStamp::from_bytes([0, 0, 0, 0, 0, 0, 0, 1, 0, 0]).iter().flat_map(|vs| {
193 let skip_because_first_is_equal = 1;
194 vs.iter().skip(skip_because_first_is_equal).map(move |vs2| (vs, vs2))
195 });
196 let versionstamps = vs.take(4).collect::<Vec<(VersionStamp, VersionStamp)>>();
197
198 assert_eq!(
199 versionstamps.len(),
200 4,
201 "We expect the combinations to be 2x2 matrix, but was {:?}",
202 versionstamps
203 );
204
205 let acceptable_values = [65536u128, 131072, 196608, 262144, 327680, 393216];
206 for (first, second) in versionstamps {
207 assert!(first < second, "First: {:?}, Second: {:?}", first, second);
208 let first = first.into_u128();
209 let second = second.into_u128();
210 assert!(acceptable_values.contains(&first));
211 assert!(acceptable_values.contains(&second));
212 }
213 }
214
215 #[test]
216 pub fn iteration_stops_past_end() {
217 let mut iter = VersionStamp::from_bytes([255; 10]).iter();
218 assert!(iter.next().is_some());
219 assert!(iter.next().is_none());
220 }
221
222 #[test]
223 fn try_to_u64_be() {
224 use super::*;
225 let v = VersionStamp::from_bytes([255, 255, 255, 255, 255, 255, 255, 255, 0, 1]);
227 let res = v.try_into_u64();
228 assert!(res.is_err());
229 let v = VersionStamp::from_bytes([255, 255, 255, 255, 255, 255, 255, 255, 0, 0]);
231 let res = v.try_into_u64().unwrap();
232 assert_eq!(res, u64::MAX);
233 }
234
235 #[test]
236 fn try_u128_to_versionstamp() {
237 use super::*;
238 let v = u128::MAX;
240 let res = VersionStamp::try_from_u128(v);
241 assert!(res.is_err());
242 let v = u128::MAX >> 48;
244 let res = VersionStamp::try_from_u128(v).unwrap();
245 assert_eq!(res.as_bytes(), [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
246 }
247
248 #[test]
249 fn can_add_u64_conversion() {
250 let start = 5u64;
251 let vs = VersionStamp::from_u64(start);
252 assert_eq!("00000000000000050000", hex::encode(vs.as_bytes()));
254 let mid = vs.try_into_u64().unwrap();
255 assert_eq!(start, mid);
256 let mid = mid + 1;
257 let vs = VersionStamp::from_u64(mid);
258 assert_eq!("00000000000000060000", hex::encode(vs.as_bytes()));
260 let end = vs.try_into_u64().unwrap();
261 assert_eq!(end, 6);
262 }
263}