uuidv6/
lib.rs

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/// A 6 bytes spatially unique identifier.
14#[derive(Default, Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
15pub struct Node {
16    node_id: [u8; 6],
17}
18
19impl Node {
20    /// Create a random node identifier
21    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    /// Create a node identifier from a byte array
28    pub fn from_bytes(bytes: &[u8; 6]) -> Self {
29        Node { node_id: *bytes }
30    }
31
32    /// Create a standard UUIDv6 base object
33    pub fn uuidv6(&self) -> UUIDv6 {
34        UUIDv6::new(self)
35    }
36
37    /// Create a raw UUIDv6 base object - Raw UUIDv6 is a 16 byte binary array, not a string
38    pub fn uuidv6_raw(&self) -> RawUUIDv6 {
39        RawUUIDv6::new(self)
40    }
41}
42
43/// A raw UUIDv6 is a 16 bytes array
44#[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/// A regular UUIDv6 is a 36 bytes string
53#[derive(Default, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
54pub struct UUIDv6 {
55    raw: RawUUIDv6,
56}
57
58impl RawUUIDv6 {
59    /// Create a new UUIDv6 base object
60    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    /// Return the next UUIDv6 as bytes
78    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    /// Return the next UUIDv6 string
104    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}