1use std::sync::atomic::{AtomicU64, Ordering};
13use std::time::{SystemTime, UNIX_EPOCH};
14
15static COUNTER: AtomicU64 = AtomicU64::new(0);
17
18#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
22pub struct Id([u8; 16]);
23
24impl Id {
25 pub fn now() -> Self {
29 let timestamp = SystemTime::now()
30 .duration_since(UNIX_EPOCH)
31 .unwrap()
32 .as_millis() as u64;
33
34 let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
36
37 let mut bytes = [0u8; 16];
38
39 bytes[0] = (timestamp >> 40) as u8;
41 bytes[1] = (timestamp >> 32) as u8;
42 bytes[2] = (timestamp >> 24) as u8;
43 bytes[3] = (timestamp >> 16) as u8;
44 bytes[4] = (timestamp >> 8) as u8;
45 bytes[5] = timestamp as u8;
46
47 bytes[6] = (counter >> 8) as u8;
49 bytes[7] = counter as u8;
50
51 let random_seed = timestamp
53 .wrapping_mul(6364136223846793005)
54 .wrapping_add(counter);
55 bytes[8] = (random_seed >> 56) as u8;
56 bytes[9] = (random_seed >> 48) as u8;
57 bytes[10] = (random_seed >> 40) as u8;
58 bytes[11] = (random_seed >> 32) as u8;
59 bytes[12] = (random_seed >> 24) as u8;
60 bytes[13] = (random_seed >> 16) as u8;
61 bytes[14] = (random_seed >> 8) as u8;
62 bytes[15] = random_seed as u8;
63
64 Self(bytes)
65 }
66
67 pub fn from_bytes(bytes: [u8; 16]) -> Self {
69 Self(bytes)
70 }
71
72 pub fn as_bytes(&self) -> &[u8; 16] {
74 &self.0
75 }
76
77 pub fn timestamp_ms(&self) -> u64 {
79 ((self.0[0] as u64) << 40)
80 | ((self.0[1] as u64) << 32)
81 | ((self.0[2] as u64) << 24)
82 | ((self.0[3] as u64) << 16)
83 | ((self.0[4] as u64) << 8)
84 | (self.0[5] as u64)
85 }
86
87 pub fn nil() -> Self {
89 Self([0u8; 16])
90 }
91
92 pub fn is_nil(&self) -> bool {
94 self.0 == [0u8; 16]
95 }
96}
97
98impl std::fmt::Display for Id {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 for byte in &self.0 {
102 write!(f, "{:02x}", byte)?;
103 }
104 Ok(())
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use std::thread;
112 use std::time::Duration;
113
114 #[test]
115 fn test_id_creation() {
116 let id = Id::now();
117 assert!(!id.is_nil());
118 }
119
120 #[test]
121 fn test_id_timestamp() {
122 let before = SystemTime::now()
123 .duration_since(UNIX_EPOCH)
124 .unwrap()
125 .as_millis() as u64;
126
127 let id = Id::now();
128
129 let after = SystemTime::now()
130 .duration_since(UNIX_EPOCH)
131 .unwrap()
132 .as_millis() as u64;
133
134 let ts = id.timestamp_ms();
135 assert!(ts >= before);
136 assert!(ts <= after);
137 }
138
139 #[test]
140 fn test_id_ordering() {
141 let id1 = Id::now();
142 thread::sleep(Duration::from_millis(2));
143 let id2 = Id::now();
144
145 assert!(id2 > id1);
147 }
148
149 #[test]
150 fn test_id_from_bytes() {
151 let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
152 let id = Id::from_bytes(bytes);
153 assert_eq!(id.as_bytes(), &bytes);
154 }
155
156 #[test]
157 fn test_id_nil() {
158 let nil = Id::nil();
159 assert!(nil.is_nil());
160 assert_eq!(nil.timestamp_ms(), 0);
161 }
162
163 #[test]
164 fn test_id_display() {
165 let id = Id::from_bytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
166 let display = format!("{}", id);
167 assert_eq!(display, "000102030405060708090a0b0c0d0e0f");
168 }
169}