1#![doc(html_root_url = "https://docs.rs/simple-uuid")]
16#![feature(doc_cfg)]
17
18mod name;
19mod rand;
20mod time;
21
22use core::fmt;
23use core::sync::atomic;
24use std::string::ToString;
25use std::time::SystemTime;
26
27use rand_core::{OsRng, RngCore};
28
29pub const UTC_EPOCH: u64 = 0x1b21_dd21_3814_000;
31
32#[derive(Debug, Default)]
34pub struct Layout {
35 pub field_low: u32,
37 pub field_mid: u16,
39 pub field_high_and_version: u16,
41 pub clock_seq_high_and_reserved: u8,
43 pub clock_seq_low: u8,
45 pub node: Node,
47}
48
49impl Layout {
50 pub fn be_fields(&self) -> (u32, u16, u16, u16, Node) {
52 (
53 self.field_low.to_be(),
54 self.field_mid.to_be(),
55 self.field_high_and_version.to_be(),
56 ((self.clock_seq_high_and_reserved as u16) << 8 | self.clock_seq_low as u16).to_be(),
57 self.node,
58 )
59 }
60
61 pub fn as_fields(&self) -> (u32, u16, u16, u16, Node) {
63 (
64 self.field_low.to_le(),
65 self.field_mid.to_le(),
66 self.field_high_and_version.to_le(),
67 ((self.clock_seq_high_and_reserved as u16) << 8 | self.clock_seq_low as u16).to_le(),
68 self.node,
69 )
70 }
71
72 pub fn be_bytes(&self) -> UUID {
74 UUID([
75 self.field_low.to_be_bytes()[0],
76 self.field_low.to_be_bytes()[1],
77 self.field_low.to_be_bytes()[2],
78 self.field_low.to_be_bytes()[3],
79 self.field_mid.to_be_bytes()[0],
80 self.field_mid.to_be_bytes()[1],
81 self.field_high_and_version.to_be_bytes()[0],
82 self.field_high_and_version.to_be_bytes()[1],
83 self.clock_seq_high_and_reserved,
84 self.clock_seq_low,
85 self.node.0[0],
86 self.node.0[1],
87 self.node.0[2],
88 self.node.0[3],
89 self.node.0[4],
90 self.node.0[5],
91 ])
92 }
93
94 pub fn as_bytes(&self) -> UUID {
96 UUID([
97 self.field_low.to_le_bytes()[3],
98 self.field_low.to_le_bytes()[2],
99 self.field_low.to_le_bytes()[1],
100 self.field_low.to_le_bytes()[0],
101 self.field_mid.to_le_bytes()[1],
102 self.field_mid.to_le_bytes()[0],
103 self.field_high_and_version.to_le_bytes()[1],
104 self.field_high_and_version.to_le_bytes()[0],
105 self.clock_seq_high_and_reserved,
106 self.clock_seq_low,
107 self.node.0[5],
108 self.node.0[4],
109 self.node.0[3],
110 self.node.0[2],
111 self.node.0[1],
112 self.node.0[0],
113 ])
114 }
115
116 pub const fn get_version(&self) -> Option<Version> {
118 match (self.field_high_and_version >> 12) & 0xf {
119 0x01 => Some(Version::TIME),
120 0x02 => Some(Version::DCE),
121 0x03 => Some(Version::MD5),
122 0x04 => Some(Version::RAND),
123 0x05 => Some(Version::SHA1),
124 _ => None,
125 }
126 }
127
128 pub const fn get_variant(&self) -> Option<Variant> {
130 match (self.clock_seq_high_and_reserved >> 4) & 0xf {
131 0x00 => Some(Variant::NCS),
132 0x01 => Some(Variant::RFC),
133 0x02 => Some(Variant::MS),
134 0x03 => Some(Variant::FUT),
135 _ => None,
136 }
137 }
138}
139
140#[derive(Debug, Eq, PartialEq)]
142pub enum Variant {
143 NCS = 0,
145 RFC,
147 MS,
149 FUT,
151}
152
153#[derive(Debug, Eq, PartialEq)]
155pub enum Version {
156 TIME = 1,
158 DCE,
160 MD5,
162 RAND,
164 SHA1,
166}
167
168#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
171pub struct TimeStamp(u64);
172
173impl TimeStamp {
174 pub fn new() -> u64 {
176 let utc = SystemTime::now()
177 .duration_since(SystemTime::UNIX_EPOCH)
178 .expect("elapsed time ")
179 .checked_add(std::time::Duration::from_nanos(UTC_EPOCH))
180 .expect("duration addition error")
181 .as_nanos();
182 (utc & 0xffff_ffff_ffff_fff) as u64
183 }
184}
185
186#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
188pub struct UUID([u8; 16]);
189
190impl UUID {
191 pub const NAMESPACE_DNS: UUID = UUID([
193 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
194 0xc8,
195 ]);
196
197 pub const NAMESPACE_OID: UUID = UUID([
199 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
200 0xc8,
201 ]);
202
203 pub const NAMESPACE_URL: UUID = UUID([
205 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
206 0xc8,
207 ]);
208
209 pub const NAMESPACE_X500: UUID = UUID([
211 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
212 0xc8,
213 ]);
214}
215
216impl fmt::LowerHex for UUID {
217 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
218 write!(
219 fmt,
220 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
221 self.0[0],
222 self.0[1],
223 self.0[2],
224 self.0[3],
225 self.0[4],
226 self.0[5],
227 self.0[6],
228 self.0[7],
229 self.0[8],
230 self.0[9],
231 self.0[10],
232 self.0[11],
233 self.0[12],
234 self.0[13],
235 self.0[14],
236 self.0[15],
237 )
238 }
239}
240
241impl fmt::UpperHex for UUID {
242 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
243 write!(
244 fmt,
245 "{:02X}{:02X}{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
246 self.0[0],
247 self.0[1],
248 self.0[2],
249 self.0[3],
250 self.0[4],
251 self.0[5],
252 self.0[6],
253 self.0[7],
254 self.0[8],
255 self.0[9],
256 self.0[10],
257 self.0[11],
258 self.0[12],
259 self.0[13],
260 self.0[14],
261 self.0[15],
262 )
263 }
264}
265
266impl ToString for UUID {
267 fn to_string(&self) -> String {
268 format!(
269 "{:02}{:02}{:02}{:02}-{:02}{:02}-{:02}{:02}-{:02}{:02}-{:02}{:02}{:02}{:02}{:02}{:02}",
270 self.0[0],
271 self.0[1],
272 self.0[2],
273 self.0[3],
274 self.0[4],
275 self.0[5],
276 self.0[6],
277 self.0[7],
278 self.0[8],
279 self.0[9],
280 self.0[10],
281 self.0[11],
282 self.0[12],
283 self.0[13],
284 self.0[14],
285 self.0[15],
286 )
287 }
288}
289
290pub struct ClockSeq(u16);
292
293impl ClockSeq {
294 pub fn new(r: u16) -> u16 {
296 atomic::AtomicU16::new(r).fetch_add(1, atomic::Ordering::SeqCst)
297 }
298}
299
300fn clock_seq_high_and_reserved(s: u8) -> (u8, u8) {
301 let mut key = [0u8; 2];
302 OsRng.fill_bytes(&mut key);
303 let random_u64 = (OsRng.next_u64() & 0xff) as u16;
304 let clock_seq = ClockSeq::new(random_u64);
305 (
306 ((clock_seq >> 8) & 0xf) as u8 | s << 4,
307 (clock_seq & 0xff) as u8,
308 )
309}
310#[derive(Debug, PartialEq, Default, Copy, Clone)]
313pub struct Node(pub [u8; 6]);
314
315impl fmt::LowerHex for Node {
316 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(
318 fmt,
319 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
320 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
321 )
322 }
323}
324
325impl fmt::UpperHex for Node {
326 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
327 write!(
328 fmt,
329 "{:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}",
330 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
331 )
332 }
333}
334
335impl ToString for Node {
336 fn to_string(&self) -> String {
337 format!(
338 "{:02}-{:02}-{:02}-{:02}-{:02}-{:02}",
339 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
340 )
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347
348 #[test]
349 fn default_value() {
350 let node = Node::default();
351 assert_eq!(node, Node([0; 6]));
352
353 let uuid = UUID::default();
354 assert_eq!(uuid, UUID([0; 16]));
355
356 let time: TimeStamp = TimeStamp::default();
357 assert_eq!(time.0.leading_zeros(), 64)
358 }
359
360 #[test]
361 fn to_string() {
362 let node = Node::default();
363 assert_eq!(node.to_string(), "00-00-00-00-00-00");
364
365 let uuid = UUID::default();
366 assert_eq!(uuid.to_string(), "00000000-0000-0000-0000-000000000000");
367 }
368}