simple_uuid/
lib.rs

1//! This crate defines a uniform resource name namespace for UUIDs
2//! (Universally Unique IDentifier), also known as GUIDs (Globally
3//! Unique Identifier). A UUID is 128 bits long, and can guarantee
4//! uniqueness across space and time.
5//!
6//! ```toml
7//! [dependencies]
8//! simple-uuid = { version = "*", features = ["rand_num"] }
9//! ```
10//!
11//! ```rust
12//! use simple_uuid::v4;
13//! println!("{}", v4!());
14//! ```
15#![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
29/// Is 100-ns ticks between UNIX and UTC epochs.
30pub const UTC_EPOCH: u64 = 0x1b21_dd21_3814_000;
31
32/// The UUID format is 16 octets.
33#[derive(Debug, Default)]
34pub struct Layout {
35    /// The low field of the Timestamp.
36    pub field_low: u32,
37    /// The mid field of the Timestamp.
38    pub field_mid: u16,
39    /// The high field of the Timestamp multiplexed with the version number.
40    pub field_high_and_version: u16,
41    /// The high field of the ClockSeq multiplexed with the variant.
42    pub clock_seq_high_and_reserved: u8,
43    /// The low field of the ClockSeq.
44    pub clock_seq_low: u8,
45    /// IEEE 802 MAC-address.
46    pub node: Node,
47}
48
49impl Layout {
50    /// Returns the five field values of the UUID in big-endian order.
51    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    /// Returns the five field values of the UUID in little-endian order.
62    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    /// Return the memory representation of the UUID in big-endian order .
73    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    /// Return the memory representation of the UUID in little-endian order .
95    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    /// Version of the current generated UUID.
117    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    /// Variant field of the current generated UUID.
129    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/// Variant is a type field determines the layout of the UUID.
141#[derive(Debug, Eq, PartialEq)]
142pub enum Variant {
143    /// Reserved, NCS backward compatibility.
144    NCS = 0,
145    /// The variant specified in `rfc4122` document.
146    RFC,
147    /// Reserved, Microsoft Corporation backward compatibility.
148    MS,
149    /// Reserved for future definition.
150    FUT,
151}
152
153/// Version represents the type of UUID, and is in the most significant 4 bits of the Timestamp.
154#[derive(Debug, Eq, PartialEq)]
155pub enum Version {
156    /// The time-based version specified in `rfc4122` document.
157    TIME = 1,
158    /// DCE Security version, with embedded POSIX UIDs.
159    DCE,
160    /// The name-based version specified in `rfc4122` document that uses MD5 hashing.
161    MD5,
162    /// The randomly or pseudo-randomly generated version specified in `rfc4122` document.
163    RAND,
164    /// The name-based version specified in `rfc4122`document that uses SHA-1 hashing.
165    SHA1,
166}
167
168/// Represented by Coordinated Universal Time (UTC) as a count
169/// of 100-ns intervals from the system-time.
170#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
171pub struct TimeStamp(u64);
172
173impl TimeStamp {
174    /// Generate new UTC timestamp.
175    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/// Is a 128-bit number used to identify information in computer systems.
187#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
188pub struct UUID([u8; 16]);
189
190impl UUID {
191    /// UUID namespace for domain name system (DNS).
192    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    /// UUID namespace for ISO object identifiers (OIDs).
198    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    /// UUID namespace for uniform resource locators (URLs).
204    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    /// UUID namespace for X.500 distinguished names (DNs).
210    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
290/// Used to avoid duplicates that could arise when the clock is set backwards in time.
291pub struct ClockSeq(u16);
292
293impl ClockSeq {
294    /// New atomic random value.
295    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/// Node field consists of an IEEE 802 MAC address,
311/// usually the host address
312#[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}