nuuid/
lib.rs

1//! Create and use UUID's
2#![cfg_attr(not(any(test, feature = "std")), no_std)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4use core::{
5    convert::TryInto,
6    fmt,
7    str::{from_utf8_unchecked_mut, FromStr},
8};
9
10use hex_simd::{decode_inplace, AsciiCase::Lower, Out};
11use md5::{Digest, Md5};
12#[cfg(feature = "getrandom")]
13use rand_chacha::rand_core::OsRng;
14use rand_chacha::{
15    rand_core::{RngCore, SeedableRng},
16    ChaChaRng,
17};
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20use sha1::Sha1;
21
22const UUID_STR_LENGTH: usize = 36;
23const UUID_URN_LENGTH: usize = 45;
24const UUID_BRACED_LENGTH: usize = 38;
25const UUID_SIMPLE_LENGTH: usize = 32;
26const UUID_URN: &str = "urn:uuid:";
27const UUID_URN_PREFIX: usize = UUID_URN.len();
28
29/// The predefined DNS namespace, 6ba7b810-9dad-11d1-80b4-00c04fd430c8.
30pub const NAMESPACE_DNS: Uuid = Uuid::from_bytes([
31    107, 167, 184, 16, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
32]);
33
34/// The predefined URL namespace, 6ba7b811-9dad-11d1-80b4-00c04fd430c8.
35pub const NAMESPACE_URL: Uuid = Uuid::from_bytes([
36    107, 167, 184, 17, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
37]);
38
39/// The predefined OID namespace, 6ba7b812-9dad-11d1-80b4-00c04fd430c8.
40pub const NAMESPACE_OID: Uuid = Uuid::from_bytes([
41    107, 167, 184, 18, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
42]);
43
44/// The predefined X500 namespace, 6ba7b814-9dad-11d1-80b4-00c04fd430c8.
45pub const NAMESPACE_X500: Uuid = Uuid::from_bytes([
46    107, 167, 184, 20, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
47]);
48
49/// A 16 byte with the UUID.
50pub type Bytes = [u8; 16];
51
52/// A CSPRNG suitable for generating UUID's.
53#[derive(Debug, Clone)]
54pub struct Rng(ChaChaRng);
55
56impl Rng {
57    /// Create a new Rng using getrandom.
58    #[cfg(feature = "getrandom")]
59    #[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
60    #[inline]
61    pub fn new() -> Self {
62        Self(ChaChaRng::from_rng(OsRng).unwrap())
63    }
64
65    /// Create a new Rng from a provided seed.
66    #[inline]
67    pub fn from_seed(seed: [u8; 32]) -> Self {
68        Self(ChaChaRng::from_seed(seed))
69    }
70
71    /// Forward to rand's fill_bytes
72    #[inline]
73    fn fill_bytes(&mut self, dest: &mut [u8]) {
74        self.0.fill_bytes(dest)
75    }
76}
77
78#[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
79#[cfg(feature = "getrandom")]
80impl Default for Rng {
81    #[inline]
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87/// UUID Variants
88#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
89#[non_exhaustive]
90pub enum Variant {
91    /// Reserved for NCS backward compatibility.
92    Ncs,
93
94    /// RFC 4122 conforming UUID's.
95    Rfc4122,
96
97    /// Reserved for legacy Microsoft backward compatibility.
98    Microsoft,
99
100    /// Reserved for the future.
101    Reserved,
102}
103
104impl fmt::Display for Variant {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        match self {
107            Variant::Ncs => write!(f, "Ncs"),
108            Variant::Rfc4122 => write!(f, "Rfc4122"),
109            Variant::Microsoft => write!(f, "Microsoft"),
110            Variant::Reserved => write!(f, "Reserved"),
111        }
112    }
113}
114
115/// UUID Version
116#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
117#[non_exhaustive]
118pub enum Version {
119    /// Special case for the nil UUID.
120    Nil = 0,
121
122    /// Version 1, time based.
123    Time,
124
125    /// Version 2, DCE Security.
126    Dce,
127
128    /// Version 3, MD5 name based.
129    Md5,
130
131    /// Version 4, random.
132    Random,
133
134    /// Version 5, SHA-1 name based.
135    Sha1,
136
137    /// Version 6, re-ordered version of [`Version::time`] for DB locality.
138    #[cfg(feature = "experimental_uuid")]
139    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
140    Database,
141
142    /// Version 7, unix time based.
143    #[cfg(feature = "experimental_uuid")]
144    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
145    UnixTime,
146
147    /// Version 8, experimental or vendor specific format
148    #[cfg(feature = "experimental_uuid")]
149    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
150    Vendor,
151
152    /// Reserved versions. Currently, versions 9-15 are reserved.
153    Reserved,
154}
155
156impl fmt::Display for Version {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        match self {
159            Version::Nil => write!(f, "Nil"),
160            Version::Time => write!(f, "Time"),
161            Version::Dce => write!(f, "Dce"),
162            Version::Md5 => write!(f, "Md5"),
163            Version::Random => write!(f, "Random"),
164            Version::Sha1 => write!(f, "Sha1"),
165
166            #[cfg(feature = "experimental_uuid")]
167            Version::Database => write!(f, "Database"),
168            #[cfg(feature = "experimental_uuid")]
169            Version::UnixTime => write!(f, "UnixTime"),
170            #[cfg(feature = "experimental_uuid")]
171            Version::Vendor => write!(f, "Vendor"),
172
173            Version::Reserved => write!(f, "Reserved"),
174        }
175    }
176}
177
178/// Error parsing UUID
179#[derive(Debug)]
180pub struct ParseUuidError;
181
182impl fmt::Display for ParseUuidError {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(f, "ParseUuidError")
185    }
186}
187
188#[cfg(any(test, feature = "std"))]
189#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
190impl std::error::Error for ParseUuidError {}
191
192/// Universally Unique Identifier, or UUID.
193///
194/// This type is `repr(transparent)` and guaranteed to have the same layout
195/// as `[u8; 16]`.
196///
197/// The various methods on `Uuid` assume each field
198/// is laid out Most Significant Byte First/MSB/Big-Endian/Network Endian.
199///
200/// This type is also `serde(transparent)`, when serde is enabled.
201#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
203#[repr(transparent)]
204pub struct Uuid(Bytes);
205
206impl Uuid {
207    /// Set the UUID Version.
208    #[inline]
209    fn set_version(&mut self, ver: Version) {
210        // `Version` enum matches version layout
211        self.0[6] = (self.0[6] & 0xF) | ((ver as u8) << 4);
212    }
213
214    /// Set the UUID Variant, only touching bits as specified.
215    ///
216    /// The version field has several unspecified bits, which this method
217    /// leaves alone. Legacy UUID's can thus be modified losslessly.
218    ///
219    /// When creating UUID's, these unspecified bits should always be zero by
220    /// default anyway.
221    #[inline]
222    fn set_variant(&mut self, ver: Variant) {
223        let byte = self.0[8];
224        self.0[8] = match ver {
225            // 0xx
226            Variant::Ncs => byte & 0x7F,
227            // 10x
228            Variant::Rfc4122 => (byte & 0x3F) | 0x80,
229            // 110
230            Variant::Microsoft => (byte & 0x1F) | 0xC0,
231            // 111
232            Variant::Reserved => byte | 0xE0,
233        }
234    }
235
236    /// Swap the in-memory format between big-endian and mixed-endian.
237    #[inline]
238    const fn swap_endian(mut self) -> Self {
239        // TODO: Const slice reverse pls. or const mem::swap.
240        let (a1, a2, a3, a4) = (self.0[0], self.0[1], self.0[2], self.0[3]);
241        self.0[0] = a4;
242        self.0[1] = a3;
243        self.0[2] = a2;
244        self.0[3] = a1;
245
246        let (a1, a2) = (self.0[4], self.0[5]);
247        self.0[4] = a2;
248        self.0[5] = a1;
249
250        let (a1, a2) = (self.0[6], self.0[7]);
251        self.0[6] = a2;
252        self.0[7] = a1;
253
254        self
255    }
256}
257
258impl Uuid {
259    /// The special Nil UUID, where all bits are set to zero.
260    #[inline]
261    pub const fn nil() -> Self {
262        Uuid([0; 16])
263    }
264
265    /// The special Max UUID, where all bits are set to one.
266    #[inline]
267    #[cfg(feature = "experimental_uuid")]
268    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
269    pub const fn max() -> Self {
270        Uuid([1; 16])
271    }
272
273    /// Create a UUID from bytes.
274    #[inline]
275    pub const fn from_bytes(bytes: Bytes) -> Self {
276        Self(bytes)
277    }
278
279    /// Return the UUID as it's bytes.
280    #[inline]
281    pub const fn to_bytes(self) -> Bytes {
282        self.0
283    }
284
285    /// Create a UUID from mixed-endian bytes.
286    ///
287    /// The resulting UUID will be stored in-memory as big-endian.
288    ///
289    /// This will primarily come up when interacting with Microsoft GUIDs/UUIDs
290    ///
291    /// The following fields are expected to be little-endian instead of
292    /// big-endian:
293    ///
294    /// - `time_low`
295    /// - `time_mid`
296    /// - `time_hi_and_version`
297    ///
298    /// Other fields are left unchanged
299    #[inline]
300    pub const fn from_bytes_me(bytes: Bytes) -> Self {
301        Self(bytes).swap_endian()
302    }
303
304    /// Return the UUID as mixed-endian bytes.
305    ///
306    /// See [`Uuid::from_bytes_me`] for details.
307    #[inline]
308    pub const fn to_bytes_me(self) -> Bytes {
309        self.swap_endian().to_bytes()
310    }
311
312    /// Returns true if the UUID is nil.
313    #[inline]
314    pub const fn is_nil(self) -> bool {
315        // Done this way for const reasons
316        // nil is nil regardless of byte order
317        u128::from_ne_bytes(self.0) == 0
318    }
319
320    /// The UUID Variant
321    ///
322    /// # Warning
323    ///
324    /// Many UUIDs out in the wild are incorrectly generated,
325    /// so this value can't be relied upon.
326    #[inline]
327    pub const fn variant(self) -> Variant {
328        // Check the highest 3 bits, skipping the 5 bits of the time/clock sequence
329        let byte = (self.0[8] >> 5) & 0b111;
330
331        // Done this way for exhaustiveness checking.
332        match (
333            // Msb0
334            byte >> 2 & 1 == 1,
335            // Msb1
336            byte >> 1 & 1 == 1,
337            // Msb2
338            byte & 1 == 1,
339        ) {
340            (false, ..) => Variant::Ncs,
341            (true, false, ..) => Variant::Rfc4122,
342            (true, true, false) => Variant::Microsoft,
343            (true, true, true) => Variant::Reserved,
344        }
345    }
346
347    /// The UUID Version
348    ///
349    /// For "incorrect" or non-RFC UUIDs, this value may be nonsensical.
350    ///
351    /// If the version bits do not match any known version,
352    /// [`Version::Reserved`] is returned instead.
353    /// As new versions are recognized, this may change.
354    ///
355    /// # Warning
356    ///
357    /// Many UUIDs out in the wild are incorrectly generated,
358    /// so this value can't be relied upon.
359    #[inline]
360    pub const fn version(self) -> Version {
361        // Check the highest 4 bits
362        match (
363            self.0[6] >> 7 & 1 == 1,
364            self.0[6] >> 6 & 1 == 1,
365            self.0[6] >> 5 & 1 == 1,
366            self.0[6] >> 4 & 1 == 1,
367        ) {
368            (false, false, false, false) => Version::Nil,
369            (false, false, false, true) => Version::Time,
370            (false, false, true, false) => Version::Dce,
371            (false, false, true, true) => Version::Md5,
372            (false, true, false, false) => Version::Random,
373            (false, true, false, true) => Version::Sha1,
374
375            #[cfg(feature = "experimental_uuid")]
376            (false, true, true, false) => Version::Database,
377
378            #[cfg(feature = "experimental_uuid")]
379            (false, true, true, true) => Version::UnixTime,
380
381            #[cfg(feature = "experimental_uuid")]
382            (true, false, false, false) => Version::Vendor,
383
384            _ => Version::Reserved,
385        }
386    }
387
388    /// The 60-bit UUID timestamp
389    ///
390    /// This value will only make sense for [`Version::Time`] or
391    /// [`Version::Database`] UUIDs
392    ///
393    /// The value of this will depend on [`Uuid::version`]
394    #[inline]
395    pub const fn timestamp(self) -> u64 {
396        match self.version() {
397            #[cfg(feature = "experimental_uuid")]
398            Version::Database => u64::from_be_bytes([
399                // Clear version bits
400                self.0[6] & 0xF,
401                self.0[7],
402                self.0[4],
403                self.0[5],
404                self.0[0],
405                self.0[1],
406                self.0[2],
407                self.0[3],
408            ]),
409            // #[cfg(feature = "experimental_uuid")]
410            // Version::UnixTime => todo!(),
411            _ => u64::from_be_bytes([
412                // Clear version bits
413                self.0[6] & 0xF,
414                self.0[7],
415                self.0[4],
416                self.0[5],
417                self.0[0],
418                self.0[1],
419                self.0[2],
420                self.0[3],
421            ]),
422        }
423    }
424
425    /// The 14-bit UUID clock sequence
426    ///
427    /// This value will only make sense for [`Version::Time`] or
428    /// [`Version::Database`] UUIDs
429    ///
430    /// The value of this will depend on [`Uuid::version`]
431    #[inline]
432    pub const fn clock_sequence(self) -> u16 {
433        u16::from_be_bytes([
434            // Clear variant bits
435            // Only need to clear two because this only makes sense for RFC UUIDs
436            self.0[8] & 0x3F,
437            self.0[9],
438        ])
439    }
440
441    /// The 48-bit UUID Node ID
442    #[inline]
443    pub const fn node(self) -> [u8; 6] {
444        [
445            self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15],
446        ]
447    }
448
449    /// Write UUID as a lowercase ASCII string into `buf`, and returns it as a
450    /// string.
451    ///
452    /// # Examples
453    ///
454    /// ```rust
455    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
456    /// # use nuuid::Uuid;
457    /// const EXAMPLE_UUID: &str = "662aa7c7-7598-4d56-8bcc-a72c30f998a2";
458    /// let uuid = Uuid::parse(EXAMPLE_UUID)?;
459    ///
460    /// let mut buf = [0u8; 36];
461    /// let string = uuid.to_str(&mut buf);
462    /// assert_eq!(string, EXAMPLE_UUID);
463    /// # Ok(()) }
464    /// ```
465    ///
466    /// With an array
467    ///
468    /// ```rust
469    /// # use nuuid::Uuid;
470    /// let uuid = Uuid::new_v4();
471    /// let mut buf = [0u8; 36];
472    /// let string = uuid.to_str(&mut buf);
473    /// ```
474    ///
475    /// With a slice
476    ///
477    /// ```rust
478    /// # use nuuid::Uuid;
479    /// # use std::convert::TryInto;
480    /// let uuid = Uuid::new_v4();
481    /// let mut data = [0u8; 50];
482    /// let string = uuid.to_str((&mut data[..36]).try_into().unwrap());
483    /// ```
484    ///
485    /// With a slice, incorrectly.
486    ///
487    /// The problem here is that the slices length is unconstrained, and could
488    /// be more or less than 36.
489    ///
490    /// ```rust,should_panic
491    /// # use nuuid::Uuid;
492    /// # use std::convert::TryInto;
493    /// let uuid = Uuid::new_v4();
494    /// let mut data = [0u8; 50];
495    /// let string = uuid.to_str((&mut data[..]).try_into().unwrap());
496    /// ```
497    pub fn to_str(self, buf: &mut [u8; 36]) -> &mut str {
498        // Add hyphens
499        buf[8] = b'-';
500        buf[13] = b'-';
501        buf[18] = b'-';
502        buf[23] = b'-';
503
504        let bytes = self.to_bytes();
505
506        let time_low = &bytes[..4];
507        let time_mid = &bytes[4..6];
508        let time_hi_and_version = &bytes[6..8];
509        let clock_seq_hi_and_reserved = &bytes[8..9];
510        let clock_seq_low = &bytes[9..10];
511        let node = &bytes[10..];
512
513        // Encode each field of the UUID
514        let _ = hex_simd::encode(time_low, Out::from_slice(&mut buf[..8]), Lower);
515        let _ = hex_simd::encode(time_mid, Out::from_slice(&mut buf[9..13]), Lower);
516        let _ = hex_simd::encode(
517            time_hi_and_version,
518            Out::from_slice(&mut buf[14..18]),
519            Lower,
520        );
521        let _ = hex_simd::encode(
522            clock_seq_hi_and_reserved,
523            Out::from_slice(&mut buf[19..21]),
524            Lower,
525        );
526        let _ = hex_simd::encode(clock_seq_low, Out::from_slice(&mut buf[21..23]), Lower);
527        let _ = hex_simd::encode(node, Out::from_slice(&mut buf[24..]), Lower);
528
529        debug_assert!(buf.is_ascii(), "BUG: Invalid ASCII in nuuid::Uuid::to_str");
530        // This is consistently faster than using the safe checked variant.
531        // Safety: Fully initialized with ASCII hex
532        unsafe { from_utf8_unchecked_mut(buf) }
533    }
534
535    /// Write a UUID as a lowercase ASCII string into `buf`, and return it as a
536    /// string.
537    ///
538    /// For usage examples see [`Uuid::to_str`].
539    #[inline]
540    pub fn to_urn(self, buf: &mut [u8; 45]) -> &mut str {
541        buf[..UUID_URN_PREFIX].copy_from_slice(UUID_URN.as_bytes());
542        self.to_str((&mut buf[UUID_URN_PREFIX..]).try_into().unwrap());
543        core::str::from_utf8_mut(buf).expect("BUG: Invalid UTF8")
544    }
545
546    /// [`Uuid::to_str`], but uppercase.
547    #[inline]
548    pub fn to_str_upper(self, buf: &mut [u8; 36]) -> &mut str {
549        let s = self.to_str(buf);
550        s.make_ascii_uppercase();
551        s
552    }
553
554    /// [`Uuid::to_urn`], but the UUID is uppercase.
555    #[inline]
556    pub fn to_urn_upper(self, buf: &mut [u8; 45]) -> &mut str {
557        let s = self.to_urn(buf);
558        s[UUID_URN_PREFIX..].make_ascii_uppercase();
559        s
560    }
561}
562
563impl Uuid {
564    /// Parse a [`Uuid`] from a string
565    ///
566    /// This method is case insensitive and supports the following formats:
567    ///
568    /// - `urn:uuid:` `urn:uuid:662aa7c7-7598-4d56-8bcc-a72c30f998a2`
569    /// - "Braced" `{662aa7c7-7598-4d56-8bcc-a72c30f998a2}`
570    /// - "Hyphenate" `662aa7c7-7598-4d56-8bcc-a72c30f998a2`
571    /// - "Simple" `662aa7c775984d568bcca72c30f998a2`
572    ///
573    /// # Example
574    ///
575    /// ```rust
576    /// # use nuuid::Uuid;
577    /// Uuid::parse("662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
578    /// Uuid::parse("662AA7C7-7598-4D56-8BCC-A72C30F998A2").unwrap();
579    ///
580    /// Uuid::parse("urn:uuid:662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
581    /// Uuid::parse("urn:uuid:662AA7C7-7598-4D56-8BCC-A72C30F998A2").unwrap();
582    ///
583    /// Uuid::parse("662aa7c775984d568bcca72c30f998a2").unwrap();
584    /// Uuid::parse("662AA7C775984D568BCCA72C30F998A2").unwrap();
585    ///
586    /// Uuid::parse("{662aa7c7-7598-4d56-8bcc-a72c30f998a2}").unwrap();
587    /// Uuid::parse("{662AA7C7-7598-4D56-8BCC-A72C30F998A2}").unwrap();
588    /// ```
589    pub fn parse(s: &str) -> Result<Self, ParseUuidError> {
590        // Error if input is not ASCII
591        if !s.is_ascii() {
592            return Err(ParseUuidError);
593        }
594
595        let s = match s.len() {
596            UUID_URN_LENGTH => &s[UUID_URN_PREFIX..],
597            UUID_BRACED_LENGTH => &s[1..s.len() - 1],
598            UUID_STR_LENGTH => s,
599            UUID_SIMPLE_LENGTH => {
600                return Ok(Uuid::from_bytes(
601                    u128::from_str_radix(s, 16)
602                        .map_err(|_| ParseUuidError)?
603                        .to_be_bytes(),
604                ));
605            }
606            _ => return Err(ParseUuidError),
607        };
608        let s = s.as_bytes();
609
610        let mut raw = [0; UUID_SIMPLE_LENGTH];
611        // "00000000-0000-0000-0000-000000000000"
612        //          9    14   19   24
613        // - 1
614        // "00000000000000000000000000000000"
615        //          9   13  17  21
616        // - 1
617
618        // Copy the UUID to `raw`, but without the hyphens, so we can
619        // decode it in-place.
620        // Benchmarking showed this was much faster than decoding directly
621        // to raw in-between the hyphens.
622
623        // Node data
624        raw[20..].copy_from_slice(&s[24..]);
625
626        // High bits of the clock, variant, and low bits of the clock
627        raw[16..20].copy_from_slice(&s[19..23]);
628
629        // High bits of the timestamp, and version
630        raw[12..16].copy_from_slice(&s[14..18]);
631
632        // Middle bits of the timestamp
633        raw[8..12].copy_from_slice(&s[9..13]);
634
635        // Low bits of the timestamp
636        raw[..8].copy_from_slice(&s[..8]);
637
638        let x = decode_inplace(&mut raw).map_err(|_| ParseUuidError)?;
639        Ok(Uuid::from_bytes(x.try_into().map_err(|_| ParseUuidError)?))
640    }
641
642    /// Parse a [`Uuid`] from a string that is in mixed-endian
643    ///
644    /// This method is bad and should never be needed, but there are UUIDs in
645    /// the wild that do this.
646    ///
647    /// These UUIDs are being displayed wrong, but you still need to parse them
648    /// correctly.
649    ///
650    /// See [`Uuid::from_bytes_me`] for details.
651    pub fn parse_me(s: &str) -> Result<Self, ParseUuidError> {
652        Uuid::from_str(s).map(Uuid::swap_endian)
653    }
654
655    /// Create a new Version 4(Random) UUID.
656    ///
657    /// This requires the `getrandom` feature.
658    ///
659    /// If generating a lot of UUID's very quickly, prefer [`Uuid::new_v4_rng`].
660    ///
661    /// # Example
662    ///
663    /// ```rust
664    /// # use nuuid::Uuid;
665    /// let uuid = Uuid::new_v4();
666    /// ```
667    #[cfg(feature = "getrandom")]
668    #[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
669    #[inline]
670    pub fn new_v4() -> Self {
671        let mut uuid = Uuid::nil();
672        OsRng.fill_bytes(&mut uuid.0);
673        uuid.set_variant(Variant::Rfc4122);
674        uuid.set_version(Version::Random);
675        uuid
676    }
677
678    /// Create a new Version 4(Random) UUID, using the provided [`Rng`]
679    ///
680    /// This method is useful if you need to generate a lot of UUID's very
681    /// quickly, since it won't create and seed a new RNG each time.
682    ///
683    /// Providing a good seed is left to you, however.
684    /// If a bad seed is used, the resulting UUIDs may not be
685    /// sufficiently random or unique.
686    ///
687    /// # Example
688    ///
689    /// ```rust
690    /// # use nuuid::{Rng, Uuid};
691    /// # let seed = [0; 32];
692    /// let mut rng = Rng::from_seed(seed);
693    /// for _ in 0..10 {
694    ///     let uuid = Uuid::new_v4_rng(&mut rng);
695    /// }
696    /// ```
697    #[inline]
698    pub fn new_v4_rng(rng: &mut Rng) -> Self {
699        let mut uuid = Uuid::nil();
700        rng.fill_bytes(&mut uuid.0);
701        uuid.set_variant(Variant::Rfc4122);
702        uuid.set_version(Version::Random);
703        uuid
704    }
705
706    /// Create a new Version 3 UUID with the provided name and namespace.
707    ///
708    /// # Note
709    ///
710    /// Version 3 UUID's use the obsolete MD5 algorithm,
711    /// [`Uuid::new_v5`] should be preferred.
712    ///
713    /// # Example
714    ///
715    /// ```rust
716    /// # use nuuid::{NAMESPACE_DNS, Uuid};
717    /// let uuid = Uuid::new_v3(NAMESPACE_DNS, b"example.com");
718    /// ```
719    #[inline]
720    pub fn new_v3(namespace: Uuid, name: &[u8]) -> Self {
721        let mut hasher = Md5::new();
722        hasher.update(namespace.to_bytes());
723        hasher.update(name);
724        let mut uuid = Uuid::from_bytes(hasher.finalize().into());
725        uuid.set_version(Version::Md5);
726        uuid.set_variant(Variant::Rfc4122);
727        uuid
728    }
729
730    /// Create a new Version 5 UUID with the provided name and namespace.
731    ///
732    /// # Example
733    ///
734    /// ```rust
735    /// # use nuuid::{NAMESPACE_DNS, Uuid};
736    /// let uuid = Uuid::new_v5(NAMESPACE_DNS, b"example.com");
737    /// ```
738    #[inline]
739    pub fn new_v5(namespace: Uuid, name: &[u8]) -> Self {
740        let mut hasher = Sha1::new();
741        hasher.update(namespace.to_bytes());
742        hasher.update(name);
743        let mut uuid = Uuid::from_bytes(hasher.finalize()[..16].try_into().unwrap());
744        uuid.set_version(Version::Sha1);
745        uuid.set_variant(Variant::Rfc4122);
746        uuid
747    }
748
749    /// Create a new Version 1 UUID using the provided 60-bit timestamp,
750    /// 14-bit counter, and node.
751    ///
752    /// The 4 high bits of `timestamp` are ignored
753    ///
754    /// The 2 high bits of `counter` are ignored
755    ///
756    /// # Example
757    ///
758    /// ```rust
759    /// # use nuuid::{NAMESPACE_DNS, Uuid};
760    /// # let (TIMESTAMP, RANDOM, RANDOM_OR_MAC) = (0, 0, [0; 6]);
761    /// let uuid = Uuid::new_v1(TIMESTAMP, RANDOM, RANDOM_OR_MAC);
762    /// ```
763    #[inline]
764    pub fn new_v1(timestamp: u64, counter: u16, node: [u8; 6]) -> Self {
765        let timestamp = timestamp.to_be_bytes();
766        let counter = counter.to_be_bytes();
767        Uuid::from_bytes([
768            // time_low
769            timestamp[4],
770            timestamp[5],
771            timestamp[6],
772            timestamp[7],
773            // time_mid
774            timestamp[2],
775            timestamp[3],
776            // time_hi Version, ignore highest 4 bits, skip `set_version` and set the version
777            (timestamp[0] & 0xF) | (1u8 << 4),
778            timestamp[1],
779            // clock_seq_hi Variant, skip `set_variant` and set the variant
780            (counter[0] & 0x3F) | 0x80,
781            counter[1],
782            // Node
783            node[0],
784            node[1],
785            node[2],
786            node[3],
787            node[4],
788            node[5],
789        ])
790    }
791
792    /// Create a new Version 6 UUID
793    ///
794    /// This is identical to Version 1 UUIDs (see [`Uuid::new_v1`]),
795    /// except that the timestamp fields are re-ordered
796    ///
797    /// # Example
798    ///
799    /// ```rust
800    /// # use nuuid::{NAMESPACE_DNS, Uuid};
801    /// # let (TIMESTAMP, RANDOM, PSEUDO) = (0, 0, [0; 6]);
802    /// let uuid = Uuid::new_v6(TIMESTAMP, RANDOM, PSEUDO);
803    /// ```
804    #[inline]
805    #[cfg(feature = "experimental_uuid")]
806    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
807    pub fn new_v6(timestamp: u64, counter: u16, node: [u8; 6]) -> Self {
808        // Truncate the highest 4 bits
809        // https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#section-6.1-2.14
810        let timestamp = (timestamp << 4).to_be_bytes();
811        let counter = counter.to_be_bytes();
812
813        Uuid::from_bytes([
814            // time_high
815            timestamp[0],
816            timestamp[1],
817            timestamp[2],
818            timestamp[3],
819            // time_mid
820            timestamp[4],
821            timestamp[5],
822            // time_low Version, shift 4 bits, skip `set_version` and set the version
823            (timestamp[6] >> 4) | (6u8 << 4),
824            timestamp[7],
825            // clock_seq_hi Variant, skip `set_variant` and set the variant
826            (counter[0] & 0x3F) | 0x80,
827            counter[1],
828            // Node
829            node[0],
830            node[1],
831            node[2],
832            node[3],
833            node[4],
834            node[5],
835        ])
836    }
837
838    /// Create a new Version 7 UUID
839    ///
840    /// This is similar to Version 1 and 6 UUIDs, but uses the UNIX epoch
841    /// timestamp source.
842    ///
843    /// # Example
844    ///
845    /// ```rust
846    /// # use nuuid::{NAMESPACE_DNS, Uuid};
847    /// # let (TIMESTAMP, RAND_A, RAND_B) = (0, 0, 0);
848    /// let uuid = Uuid::new_v7(TIMESTAMP, RAND_A, RAND_B);
849    /// ```
850    #[inline]
851    #[cfg(feature = "experimental_uuid")]
852    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
853    pub fn new_v7(timestamp: u64, rand_a: u16, rand_b: u64) -> Self {
854        // Truncate the highest 16 bits
855        // https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#section-6.1-2.14
856        let timestamp = (timestamp << 16).to_be_bytes();
857        let rand_a = rand_a.to_be_bytes();
858        let rand_b = rand_b.to_be_bytes();
859
860        Uuid::from_bytes([
861            // unix_ts_ms
862            timestamp[0],
863            timestamp[1],
864            timestamp[2],
865            timestamp[3],
866            timestamp[4],
867            timestamp[5],
868            // rand_a Version, ignore highest 4 bits, skip `set_version` and set the version
869            (rand_a[0] & 0xF) | (7u8 << 4),
870            rand_a[1],
871            // rand_b, Variant, skip `set_variant` and set the variant
872            (rand_b[0] & 0x3F) | 0x80,
873            rand_b[1],
874            rand_b[2],
875            rand_b[3],
876            rand_b[4],
877            rand_b[5],
878            rand_b[6],
879            rand_b[7],
880        ])
881    }
882
883    /// Create a new Version 8 UUID
884    ///
885    /// This will set the version and variant bits as needed,
886    /// and the input will otherwise be unchanged.
887    ///
888    /// # Example
889    ///
890    /// ```rust
891    /// # use nuuid::Uuid;
892    /// let uuid = Uuid::new_v8(*b"I Am 16 bytes!!!");
893    /// ```
894    #[inline]
895    #[cfg(feature = "experimental_uuid")]
896    #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
897    pub fn new_v8(bytes: Bytes) -> Self {
898        let mut uuid = Uuid::from_bytes(bytes);
899        uuid.set_variant(Variant::Rfc4122);
900        uuid.set_version(Version::Vendor);
901        uuid
902    }
903}
904
905/// See [`Uuid::parse`] for details.
906impl FromStr for Uuid {
907    type Err = ParseUuidError;
908
909    /// See [`Uuid::parse`] for details.
910    fn from_str(s: &str) -> Result<Self, Self::Err> {
911        Uuid::parse(s)
912    }
913}
914
915/// Display the [`Uuid`] in uppercase hex.
916///
917/// # Example
918///
919/// ```rust
920/// # use nuuid::Uuid;
921/// let uuid = Uuid::parse("662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
922/// assert_eq!(format!("{}", uuid), "662AA7C7-7598-4D56-8BCC-A72C30F998A2");
923/// ```
924impl fmt::Display for Uuid {
925    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926        write!(f, "{:X}", self)
927    }
928}
929
930/// Display the [`Uuid`] debug representation
931///
932/// The alternate(`#`) flag can be used to get more more detailed debug
933/// information.
934///
935/// # Example
936///
937/// ```rust
938/// # use nuuid::Uuid;
939/// let uuid = Uuid::parse("662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
940/// assert_eq!(format!("{:?}", uuid), "Uuid(662AA7C7-7598-4D56-8BCC-A72C30F998A2)");
941/// assert_eq!(format!("{:#?}", uuid), r#"Uuid(662AA7C7-7598-4D56-8BCC-A72C30F998A2) {
942///     Version: Random(4),
943///     Variant: Rfc4122(1),
944/// }"#);
945/// ```
946impl fmt::Debug for Uuid {
947    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
948        if f.alternate() {
949            write!(
950                f,
951                r#"Uuid({:X}) {{
952    Version: {}({}),
953    Variant: {}({}),
954}}"#,
955                self,
956                self.version(),
957                self.version() as u8,
958                self.variant(),
959                self.variant() as u8
960            )
961        } else {
962            write!(f, "Uuid({:X})", self)
963        }
964    }
965}
966
967/// Display the [`Uuid`] in lowercase
968///
969/// The alternate(`#`) flag can be used to get a URN.
970///
971/// # Example
972///
973/// ```rust
974/// # use nuuid::Uuid;
975/// let uuid = Uuid::parse("662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
976/// assert_eq!(format!("{:x}", uuid), "662aa7c7-7598-4d56-8bcc-a72c30f998a2");
977/// assert_eq!(format!("{:#x}", uuid), "urn:uuid:662aa7c7-7598-4d56-8bcc-a72c30f998a2");
978/// ```
979impl fmt::LowerHex for Uuid {
980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981        if f.alternate() {
982            write!(f, "{}", UUID_URN)?;
983        }
984        let mut buf = [0; 36];
985        let s = self.to_str(&mut buf);
986        write!(f, "{}", s)
987    }
988}
989
990/// Display the [`Uuid`] in uppercase
991///
992/// The alternate(`#`) flag can be used to get a URN.
993///
994/// # Example
995///
996/// ```rust
997/// # use nuuid::Uuid;
998/// let uuid = Uuid::parse("662aa7c7-7598-4d56-8bcc-a72c30f998a2").unwrap();
999/// assert_eq!(format!("{:X}", uuid), "662AA7C7-7598-4D56-8BCC-A72C30F998A2");
1000/// assert_eq!(format!("{:#X}", uuid), "urn:uuid:662AA7C7-7598-4D56-8BCC-A72C30F998A2");
1001/// ```
1002impl fmt::UpperHex for Uuid {
1003    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004        if f.alternate() {
1005            write!(f, "{}", UUID_URN)?;
1006        }
1007        let mut buf = [0; 36];
1008        write!(f, "{}", self.to_str_upper(&mut buf))
1009    }
1010}
1011
1012impl AsRef<[u8]> for Uuid {
1013    #[inline]
1014    fn as_ref(&self) -> &[u8] {
1015        &self.0
1016    }
1017}
1018
1019impl AsRef<[u8; 16]> for Uuid {
1020    #[inline]
1021    fn as_ref(&self) -> &[u8; 16] {
1022        &self.0
1023    }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028    use super::*;
1029
1030    const UUID_NIL: &str = "00000000-0000-0000-0000-000000000000";
1031    const UUID_V4: &str = "662aa7c7-7598-4d56-8bcc-a72c30f998a2";
1032    const UUID_V4_SIMPLE: &str = "662aa7c775984d568bcca72c30f998a2";
1033    const UUID_V4_BRACED: &str = "{662aa7c7-7598-4d56-8bcc-a72c30f998a2}";
1034    const UUID_V4_URN: &str = "urn:uuid:662aa7c7-7598-4d56-8bcc-a72c30f998a2";
1035    const UUID_V4_URN_UPPER: &str = "urn:uuid:662AA7C7-7598-4D56-8BCC-A72C30F998A2";
1036    const RAW: [u8; 16] = [
1037        102, 42, 167, 199, 117, 152, 77, 86, 139, 204, 167, 44, 48, 249, 152, 162,
1038    ];
1039
1040    fn name(fun: fn(Uuid, &[u8]) -> Uuid, ver: Version) {
1041        let namespace = Uuid::new_v4();
1042        let namespace2 = Uuid::new_v4();
1043        let uuid1 = fun(namespace, b"test");
1044        let uuid2 = fun(namespace, b"test");
1045        assert_eq!(
1046            uuid1, uuid2,
1047            "UUID's from different times with the same name/namespace must be equal"
1048        );
1049
1050        let uuid = fun(namespace, b"Cat");
1051        assert_ne!(
1052            uuid, uuid2,
1053            "UUID's with two different names in the same namespace must NOT be equal"
1054        );
1055
1056        let uuid = fun(namespace2, b"test");
1057        assert_ne!(
1058            uuid, uuid2,
1059            "UUID's with the same names in a different namespace must NOT be equal"
1060        );
1061
1062        assert_eq!(uuid.version(), ver);
1063        assert_eq!(uuid.variant(), Variant::Rfc4122);
1064    }
1065
1066    #[test]
1067    #[cfg(feature = "experimental_uuid")]
1068    fn new_v6() {
1069        // Values sourced from https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-test-vectors
1070        const UUID: &str = "1EC9414C-232A-6B00-B3C8-9E6BDECED846";
1071        let (ticks, counter, node) = (138648505420000000, 13256, [158, 107, 222, 206, 216, 70]);
1072
1073        let uuid = Uuid::new_v6(ticks, counter, node);
1074        let uuid_ = Uuid::parse(UUID).unwrap();
1075
1076        assert_eq!(uuid.to_str_upper(&mut [0; 36]), UUID);
1077        assert_eq!(uuid.version(), Version::Database);
1078        assert_eq!(uuid.variant(), Variant::Rfc4122);
1079
1080        assert_eq!(uuid.timestamp(), uuid_.timestamp());
1081        assert_eq!(uuid.clock_sequence(), uuid_.clock_sequence());
1082        assert_eq!(uuid.node()[..], uuid_.node());
1083    }
1084
1085    #[test]
1086    #[cfg(feature = "experimental_uuid")]
1087    fn new_v7() {
1088        // Values sourced from https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuidv7-example-test-vector
1089        const UUID: &str = "017F22E2-79B0-7CC3-98C4-DC0C0C07398F";
1090        let (unix_ts, rand_a, rand_b) = (0x17F22E279B0, 0xCC3, 0x18C4DC0C0C07398F);
1091
1092        let uuid = Uuid::new_v7(unix_ts, rand_a, rand_b);
1093        let uuid_ = Uuid::parse(UUID).unwrap();
1094
1095        assert_eq!(uuid.to_str_upper(&mut [0; 36]), UUID);
1096        assert_eq!(uuid.version(), Version::UnixTime);
1097        assert_eq!(uuid.variant(), Variant::Rfc4122);
1098
1099        assert_eq!(uuid.timestamp(), uuid_.timestamp());
1100        assert_eq!(uuid.clock_sequence(), uuid_.clock_sequence());
1101        assert_eq!(uuid.node()[..], uuid_.node());
1102    }
1103
1104    #[test]
1105    fn time() {
1106        use uuid_::{v1::*, Uuid as Uuid_};
1107        let (ticks, counter, node) = (138788330336896890u64, 8648, *b"world!");
1108
1109        let uuid = Uuid::new_v1(ticks, counter, node);
1110        let uuid_ = Uuid_::new_v1(Timestamp::from_rfc4122(ticks, counter), &node);
1111        assert_eq!(uuid.to_bytes(), *uuid_.as_bytes());
1112        assert_eq!(uuid.version(), Version::Time);
1113        assert_eq!(uuid.variant(), Variant::Rfc4122);
1114
1115        assert_eq!(
1116            uuid.timestamp(),
1117            uuid_.get_timestamp().unwrap().to_rfc4122().0
1118        );
1119        assert_eq!(
1120            uuid.clock_sequence(),
1121            uuid_.get_timestamp().unwrap().to_rfc4122().1
1122        );
1123        assert_eq!(uuid.node()[..], uuid_.as_fields().3[2..]);
1124    }
1125
1126    #[test]
1127    fn md5() {
1128        name(Uuid::new_v3, Version::Md5);
1129        let uuid = Uuid::new_v3(NAMESPACE_DNS, b"www.widgets.com");
1130        assert_eq!(
1131            uuid,
1132            // From Appendix B, with errata 1352, since RFC is wrong.
1133            // Because of course it is.
1134            Uuid::from_str("3d813cbb-47fb-32ba-91df-831e1593ac29").unwrap()
1135        )
1136    }
1137
1138    #[test]
1139    fn sha1() {
1140        name(Uuid::new_v5, Version::Sha1)
1141    }
1142
1143    #[test]
1144    fn parse_string() {
1145        let test = &[UUID_V4, UUID_V4_URN, UUID_V4_BRACED, UUID_V4_SIMPLE];
1146        for uuid in test {
1147            println!("Source UUID: {}", uuid);
1148            let uuid = Uuid::from_str(&uuid.to_ascii_lowercase()).unwrap();
1149            println!("Parsed UUID: {}\n", uuid);
1150            assert_eq!(RAW, uuid.to_bytes(), "Parsed UUID bytes don't match");
1151        }
1152
1153        for uuid in test {
1154            println!("Source UUID: {}", uuid);
1155            let uuid = Uuid::from_str(&uuid.to_ascii_uppercase()).unwrap();
1156            println!("Parsed UUID: {}\n", uuid);
1157            assert_eq!(RAW, uuid.to_bytes(), "Parsed UUID bytes don't match");
1158        }
1159    }
1160
1161    #[test]
1162    fn string() {
1163        let uuid = Uuid::from_bytes(RAW);
1164        let mut buf = [0; 45];
1165        assert_eq!(
1166            uuid.to_str((&mut buf[..36]).try_into().unwrap()),
1167            UUID_V4,
1168            "UUID strings didn't match"
1169        );
1170        assert_eq!(
1171            uuid.to_urn(&mut buf),
1172            UUID_V4_URN,
1173            "UUID URN strings didn't match"
1174        );
1175        assert_eq!(
1176            uuid.to_urn_upper(&mut buf),
1177            UUID_V4_URN_UPPER,
1178            "UUID URN upper strings didn't match"
1179        );
1180        assert_eq!(
1181            format!("{:#x}", uuid),
1182            UUID_V4_URN,
1183            "UUID URN Display didn't match"
1184        );
1185        assert_eq!(format!("{:x}", uuid), UUID_V4, "UUID Display didn't match");
1186        assert_eq!(
1187            format!("{}", uuid),
1188            UUID_V4.to_ascii_uppercase(),
1189            "UUID Display didn't match"
1190        );
1191        assert_eq!(
1192            format!("{}", Uuid::nil()),
1193            UUID_NIL,
1194            "Nil UUID Display didn't work!"
1195        );
1196    }
1197
1198    #[test]
1199    fn endian() {
1200        let uuid_be = Uuid::from_bytes(RAW);
1201        assert_eq!(uuid_be.version(), Version::Random);
1202        assert_eq!(uuid_be.variant(), Variant::Rfc4122);
1203
1204        let uuid_le = Uuid::from_bytes_me(uuid_be.to_bytes_me());
1205        assert_eq!(uuid_le.version(), Version::Random);
1206        assert_eq!(uuid_le.variant(), Variant::Rfc4122);
1207
1208        assert_eq!(uuid_le, uuid_be);
1209        assert_ne!(uuid_be.to_bytes_me(), uuid_be.to_bytes());
1210
1211        // Terrible UUID sourced from my partition table on Linux.
1212        // Either Linux displays them wrong, or parted stores them wrong.
1213        // Either way, its swapped.
1214        const UUID: &str = "20169084-b186-884f-b110-3db2c37eb8b5";
1215        let uuid = Uuid::parse_me(UUID).unwrap();
1216        let bad_uuid = Uuid::parse(UUID).unwrap();
1217
1218        assert_ne!(bad_uuid.version(), Version::Random);
1219        assert_eq!(uuid.version(), Version::Random);
1220        assert_eq!(uuid.variant(), Variant::Rfc4122);
1221        // Cant be equal because endian
1222        assert_ne!(uuid.to_str(&mut [0; 36]), UUID);
1223    }
1224
1225    #[test]
1226    fn info() {
1227        let uuid = Uuid::from_bytes(RAW);
1228        assert_eq!(uuid.version(), Version::Random);
1229        assert_eq!(uuid.variant(), Variant::Rfc4122);
1230        #[cfg(feature = "getrandom")]
1231        {
1232            let uuid = Uuid::new_v4();
1233            assert_eq!(uuid.version(), Version::Random);
1234            assert_eq!(uuid.variant(), Variant::Rfc4122);
1235        }
1236    }
1237}