grafeo_common/types/
validity.rs1use std::cmp::{Ordering, Reverse};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct ValidityTs(Reverse<i64>);
22
23impl ValidityTs {
24 #[must_use]
26 pub fn new(ts: i64) -> Self {
27 Self(Reverse(ts))
28 }
29
30 #[must_use]
35 pub fn current() -> Self {
36 Self(Reverse(i64::MAX))
37 }
38
39 #[must_use]
41 pub fn timestamp(&self) -> i64 {
42 self.0.0
43 }
44
45 #[must_use]
55 pub fn versioned_key(entity_id: u64, ts: Self) -> [u8; 16] {
56 let mut key = [0u8; 16];
57 key[..8].copy_from_slice(&entity_id.to_be_bytes());
58 key[8..].copy_from_slice(&ts.0.0.to_be_bytes());
59 key
60 }
61
62 #[must_use]
66 pub fn from_versioned_key(key: &[u8; 16]) -> (u64, Self) {
67 let entity_id = u64::from_be_bytes(key[..8].try_into().unwrap());
68 let ts = i64::from_be_bytes(key[8..].try_into().unwrap());
69 (entity_id, Self::new(ts))
70 }
71}
72
73impl Ord for ValidityTs {
74 fn cmp(&self, other: &Self) -> Ordering {
75 self.0.cmp(&other.0)
76 }
77}
78
79impl PartialOrd for ValidityTs {
80 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
81 Some(self.cmp(other))
82 }
83}
84
85impl From<i64> for ValidityTs {
86 fn from(ts: i64) -> Self {
87 Self::new(ts)
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_reverse_ordering() {
97 let ts1 = ValidityTs::new(10);
98 let ts2 = ValidityTs::new(20);
99
100 assert!(ts2 < ts1);
102 assert!(ts1 > ts2);
103 }
104
105 #[test]
106 fn test_current_sentinel() {
107 let current = ValidityTs::current();
108 let recent = ValidityTs::new(1_000_000);
109
110 assert!(current < recent);
112 assert_eq!(current.timestamp(), i64::MAX);
113 }
114
115 #[test]
116 fn test_versioned_key_roundtrip() {
117 let entity_id = 42u64;
118 let ts = ValidityTs::new(12345);
119
120 let key = ValidityTs::versioned_key(entity_id, ts);
121 let (decoded_id, decoded_ts) = ValidityTs::from_versioned_key(&key);
122
123 assert_eq!(decoded_id, entity_id);
124 assert_eq!(decoded_ts, ts);
125 }
126
127 #[test]
128 fn test_versioned_key_entity_ordering() {
129 let key1 = ValidityTs::versioned_key(1, ValidityTs::new(100));
131 let key2 = ValidityTs::versioned_key(2, ValidityTs::new(100));
132
133 assert!(key1 < key2);
134 }
135
136 #[test]
137 fn test_equality() {
138 let ts1 = ValidityTs::new(42);
139 let ts2 = ValidityTs::new(42);
140 let ts3 = ValidityTs::new(43);
141
142 assert_eq!(ts1, ts2);
143 assert_ne!(ts1, ts3);
144 }
145
146 #[test]
147 fn test_from_i64() {
148 let ts: ValidityTs = 42i64.into();
149 assert_eq!(ts.timestamp(), 42);
150 }
151}