1use coarsetime::Clock;
2
3fn hex_format(out: &mut [u8], bin: &[u8]) {
4 const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
5 let mut j = 0;
6 for b in bin {
7 out[j] = HEX_CHARS[(b >> 4) as usize];
8 out[j + 1] = HEX_CHARS[(b & 0x0f) as usize];
9 j += 2;
10 }
11}
12
13#[derive(Default, Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
15pub struct Node {
16 node_id: [u8; 6],
17}
18
19impl Node {
20 pub fn new() -> Self {
22 let mut node_id = [0u8; 6];
23 getrandom::fill(&mut node_id).unwrap();
24 Node { node_id }
25 }
26
27 pub fn from_bytes(bytes: &[u8; 6]) -> Self {
29 Node { node_id: *bytes }
30 }
31
32 pub fn uuidv6(&self) -> UUIDv6 {
34 UUIDv6::new(self)
35 }
36
37 pub fn uuidv6_raw(&self) -> RawUUIDv6 {
39 RawUUIDv6::new(self)
40 }
41}
42
43#[derive(Default, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
45pub struct RawUUIDv6 {
46 ts: u64,
47 counter: u16,
48 initial_counter: u16,
49 node: Node,
50}
51
52#[derive(Default, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
54pub struct UUIDv6 {
55 raw: RawUUIDv6,
56}
57
58impl RawUUIDv6 {
59 pub fn new(node: &Node) -> RawUUIDv6 {
61 let ts = Clock::now_since_epoch()
62 .as_nanos()
63 .checked_add(1221929280000000)
64 .expect("Time is completely off")
65 / 100;
66 let mut x = [0u8; 2];
67 getrandom::fill(&mut x).unwrap();
68 let initial_counter = u16::from_be_bytes(x);
69 RawUUIDv6 {
70 ts,
71 counter: initial_counter,
72 initial_counter,
73 node: *node,
74 }
75 }
76
77 pub fn create(&mut self) -> [u8; 16] {
79 let mut buf = [0u8; 16];
80 let ts = self.ts;
81 buf[0..8].copy_from_slice(&(ts << 4).to_be_bytes());
82 let x = (0x06u16 << 12) | (((buf[6] as u16) << 8 | buf[7] as u16) >> 4);
83 buf[6..8].copy_from_slice(&x.to_be_bytes());
84
85 buf[8..10].copy_from_slice(&self.counter.to_be_bytes());
86 self.counter = self.counter.wrapping_add(1);
87 if self.counter == self.initial_counter {
88 *self = Self::new(&self.node);
89 };
90
91 buf[10..].copy_from_slice(&self.node.node_id);
92 buf
93 }
94}
95
96impl UUIDv6 {
97 pub fn new(node: &Node) -> Self {
98 UUIDv6 {
99 raw: RawUUIDv6::new(node),
100 }
101 }
102
103 pub fn create(&mut self) -> String {
105 let buf = self.raw.create();
106
107 let mut out = [0u8; 4 + 32];
108 out[8] = b'-';
109 out[13] = b'-';
110 out[18] = b'-';
111 out[23] = b'-';
112
113 hex_format(&mut out[0..], &buf[0..4]);
114 hex_format(&mut out[9..], &buf[4..6]);
115 hex_format(&mut out[14..], &buf[6..8]);
116 hex_format(&mut out[19..], &buf[8..10]);
117 hex_format(&mut out[24..], &buf[10..]);
118
119 String::from_utf8_lossy(&out).into_owned()
120 }
121}
122
123#[derive(Default, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
124pub struct RawUUIDv6Iterator {
125 uuid: RawUUIDv6,
126}
127
128impl Iterator for RawUUIDv6Iterator {
129 type Item = [u8; 16];
130
131 fn next(&mut self) -> Option<Self::Item> {
132 Some(self.uuid.create())
133 }
134}
135
136impl IntoIterator for RawUUIDv6 {
137 type IntoIter = RawUUIDv6Iterator;
138 type Item = [u8; 16];
139
140 fn into_iter(self) -> Self::IntoIter {
141 RawUUIDv6Iterator { uuid: self }
142 }
143}
144
145#[derive(Default, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
146pub struct UUIDv6Iterator {
147 uuid: UUIDv6,
148}
149
150impl Iterator for UUIDv6Iterator {
151 type Item = String;
152
153 fn next(&mut self) -> Option<Self::Item> {
154 Some(self.uuid.create())
155 }
156}
157
158impl IntoIterator for UUIDv6 {
159 type IntoIter = UUIDv6Iterator;
160 type Item = String;
161
162 fn into_iter(self) -> Self::IntoIter {
163 UUIDv6Iterator { uuid: self }
164 }
165}
166
167#[test]
168fn test() {
169 let node = Node::new();
170
171 let mut st = node.uuidv6().into_iter();
172
173 let uid_1 = st.next();
174 let uid_2 = st.next();
175 let uid_3 = st.next();
176 debug_assert_ne!(uid_1, uid_2);
177 debug_assert_ne!(uid_2, uid_3);
178 debug_assert_ne!(uid_3, uid_1);
179}
180
181#[test]
182fn test_raw() {
183 let node = Node::new();
184
185 let mut st = node.uuidv6_raw().into_iter();
186
187 let uid_1 = st.next();
188 let uid_2 = st.next();
189 let uid_3 = st.next();
190 debug_assert_ne!(uid_1, uid_2);
191 debug_assert_ne!(uid_2, uid_3);
192 debug_assert_ne!(uid_3, uid_1);
193}