Skip to main content

bare_types/net/
uuid.rs

1//! UUID type for network programming.
2//!
3//! This module provides a type-safe abstraction for UUIDs,
4//! ensuring compliance with RFC 4122 UUID specifications.
5//!
6//! # RFC 4122 UUID Rules
7//!
8//! According to [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122):
9//!
10//! - Length: 16 bytes (128 bits)
11//! - Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (8-4-4-4-12 hex digits)
12//! - Versions: 1 (time-based), 3 (MD5), 4 (random), 5 (SHA-1)
13//! - Variants: NCS, RFC 4122, Microsoft, Future
14//! - Nil UUID: 00000000-0000-0000-0000-000000000000
15//!
16//! # Examples
17//!
18//! ```rust
19//! use bare_types::net::Uuid;
20//!
21//! // Create a UUID from bytes
22//! let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
23//!                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
24//!
25//! // Check if it's nil
26//! assert!(!uuid.is_nil());
27//!
28//! // Get the version
29//! assert_eq!(uuid.version(), None);
30//!
31//! // Get the string representation
32//! assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
33//!
34//! // Parse from string
35//! let uuid: Uuid = "00112233-4455-6677-8899-aabbccddeeff".parse()?;
36//! # Ok::<(), bare_types::net::UuidError>(())
37//! ```
38
39use core::fmt;
40use core::str::FromStr;
41
42#[cfg(feature = "serde")]
43use serde::{Deserialize, Serialize};
44
45#[cfg(feature = "zeroize")]
46use zeroize::Zeroize;
47
48/// Error type for UUID validation.
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51#[non_exhaustive]
52pub enum UuidError {
53    /// Invalid length
54    ///
55    /// UUIDs must be exactly 16 bytes (128 bits).
56    /// This variant contains the actual length.
57    InvalidLength(usize),
58    /// Invalid format
59    ///
60    /// The UUID string is not in a valid format.
61    /// Expected format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
62    InvalidFormat,
63    /// Invalid character
64    ///
65    /// The UUID contains an invalid character.
66    /// This variant contains the invalid character.
67    InvalidChar(char),
68}
69
70impl fmt::Display for UuidError {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            Self::InvalidLength(len) => {
74                write!(f, "UUID must be 16 bytes (got {len})")
75            }
76            Self::InvalidFormat => {
77                write!(
78                    f,
79                    "UUID must be in format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
80                )
81            }
82            Self::InvalidChar(c) => {
83                write!(f, "UUID contains invalid character '{c}'")
84            }
85        }
86    }
87}
88
89#[cfg(feature = "std")]
90impl std::error::Error for UuidError {}
91
92/// A UUID.
93///
94/// This type provides type-safe UUIDs with RFC 4122 validation.
95/// It uses the newtype pattern with `#[repr(transparent)]` for zero-cost abstraction.
96///
97/// # Invariants
98///
99/// - Exactly 16 bytes (128 bits)
100///
101/// # Examples
102///
103/// ```rust
104/// use bare_types::net::Uuid;
105///
106/// // Create a UUID from bytes
107/// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
108///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
109///
110/// // Access the string representation
111/// assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
112///
113/// // Check if it's nil
114/// assert!(!uuid.is_nil());
115///
116/// // Get the bytes
117/// assert_eq!(uuid.bytes(), [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
118///                          0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
119///
120/// // Parse from string
121/// let uuid: Uuid = "00112233-4455-6677-8899-aabbccddeeff".parse()?;
122/// # Ok::<(), bare_types::net::UuidError>(())
123/// ```
124#[repr(transparent)]
125#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[cfg_attr(feature = "zeroize", derive(Zeroize))]
128pub struct Uuid([u8; 16]);
129
130#[cfg(feature = "arbitrary")]
131impl<'a> arbitrary::Arbitrary<'a> for Uuid {
132    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
133        let mut bytes = [0x8; 16];
134        for byte in &mut bytes {
135            *byte = u8::arbitrary(u)?;
136        }
137        Ok(Self(bytes))
138    }
139}
140
141impl Uuid {
142    /// Creates a new UUID from an array of 16 bytes.
143    ///
144    /// # Examples
145    ///
146    /// ```rust
147    /// use bare_types::net::Uuid;
148    ///
149    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
150    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
151    /// assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
152    /// ```
153    #[must_use]
154    pub const fn new(bytes: [u8; 16]) -> Self {
155        Self(bytes)
156    }
157
158    /// Creates a new UUID from a slice of bytes.
159    ///
160    /// # Errors
161    ///
162    /// Returns `UuidError` if the slice is not exactly 16 bytes.
163    ///
164    /// # Examples
165    ///
166    /// ```rust
167    /// use bare_types::net::Uuid;
168    ///
169    /// let bytes = vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
170    ///                0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
171    /// let uuid = Uuid::from_bytes(&bytes)?;
172    /// assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
173    /// # Ok::<(), bare_types::net::UuidError>(())
174    /// ```
175    pub fn from_bytes(bytes: &[u8]) -> Result<Self, UuidError> {
176        if bytes.len() != 16 {
177            return Err(UuidError::InvalidLength(bytes.len()));
178        }
179        let mut arr = [0u8; 16];
180        arr.copy_from_slice(bytes);
181        Ok(Self(arr))
182    }
183
184    /// Creates a new UUID from a string.
185    ///
186    /// # Errors
187    ///
188    /// Returns `UuidError` if string is not in a valid format.
189    ///
190    /// # Panics
191    ///
192    /// Panics if a hex character is invalid (this should never happen due to prior validation).
193    ///
194    /// # Examples
195    ///
196    /// ```rust
197    /// use bare_types::net::Uuid;
198    ///
199    /// let uuid = Uuid::from_str("00112233-4455-6677-8899-aabbccddeeff")?;
200    /// assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
201    /// # Ok::<(), bare_types::net::UuidError>(())
202    /// ```
203    #[allow(clippy::should_implement_trait)]
204    pub fn from_str(s: &str) -> Result<Self, UuidError> {
205        if s.len() != 36 {
206            return Err(UuidError::InvalidFormat);
207        }
208
209        let chars: Vec<char> = s.chars().collect();
210
211        if chars[8] != '-' || chars[13] != '-' || chars[18] != '-' || chars[23] != '-' {
212            return Err(UuidError::InvalidFormat);
213        }
214
215        let mut bytes = [0u8; 16];
216        let mut byte_idx = 0;
217        let mut hex_idx = 0;
218
219        for c in &chars {
220            if *c == '-' {
221                continue;
222            }
223
224            if !c.is_ascii_hexdigit() {
225                return Err(UuidError::InvalidChar(*c));
226            }
227
228            let hex = u8::try_from(c.to_digit(16).unwrap()).unwrap();
229
230            if hex_idx % 2 == 0 {
231                bytes[byte_idx] = hex << 4;
232            } else {
233                bytes[byte_idx] |= hex;
234                byte_idx += 1;
235            }
236            hex_idx += 1;
237        }
238
239        Ok(Self(bytes))
240    }
241
242    /// Returns the nil UUID.
243    ///
244    /// The nil UUID is 00000000-0000-0000-0000-000000000000.
245    ///
246    /// # Examples
247    ///
248    /// ```rust
249    /// use bare_types::net::Uuid;
250    ///
251    /// let uuid = Uuid::nil();
252    /// assert!(uuid.is_nil());
253    /// assert_eq!(uuid.as_str(), "00000000-0000-0000-0000-000000000000");
254    /// ```
255    #[must_use]
256    #[inline]
257    pub const fn nil() -> Self {
258        Self([0u8; 16])
259    }
260
261    /// Returns the UUID as a string in standard format.
262    ///
263    /// # Examples
264    ///
265    /// ```rust
266    /// use bare_types::net::Uuid;
267    ///
268    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
269    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
270    /// assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
271    /// ```
272    #[must_use]
273    pub fn as_str(&self) -> String {
274        format!(
275            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
276            self.0[0],
277            self.0[1],
278            self.0[2],
279            self.0[3],
280            self.0[4],
281            self.0[5],
282            self.0[6],
283            self.0[7],
284            self.0[8],
285            self.0[9],
286            self.0[10],
287            self.0[11],
288            self.0[12],
289            self.0[13],
290            self.0[14],
291            self.0[15]
292        )
293    }
294
295    /// Returns the UUID as a string in uppercase format.
296    ///
297    /// # Examples
298    ///
299    /// ```rust
300    /// use bare_types::net::Uuid;
301    ///
302    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
303    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
304    /// assert_eq!(uuid.as_str_upper(), "00112233-4455-6677-8899-AABBCCDDEEFF");
305    /// ```
306    #[must_use]
307    pub fn as_str_upper(&self) -> String {
308        format!(
309            "{:02X}{:02X}{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
310            self.0[0],
311            self.0[1],
312            self.0[2],
313            self.0[3],
314            self.0[4],
315            self.0[5],
316            self.0[6],
317            self.0[7],
318            self.0[8],
319            self.0[9],
320            self.0[10],
321            self.0[11],
322            self.0[12],
323            self.0[13],
324            self.0[14],
325            self.0[15]
326        )
327    }
328
329    /// Returns a reference to the underlying array of 16 bytes.
330    ///
331    /// # Examples
332    ///
333    /// ```rust
334    /// use bare_types::net::Uuid;
335    ///
336    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
337    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
338    /// let bytes: &[u8; 16] = uuid.as_inner();
339    /// assert_eq!(bytes, &[0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
340    ///                       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
341    /// ```
342    #[must_use]
343    #[inline]
344    pub const fn as_inner(&self) -> &[u8; 16] {
345        &self.0
346    }
347
348    /// Consumes this UUID and returns the underlying array of 16 bytes.
349    ///
350    /// # Examples
351    ///
352    /// ```rust
353    /// use bare_types::net::Uuid;
354    ///
355    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
356    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
357    /// let bytes = uuid.into_inner();
358    /// assert_eq!(bytes, [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
359    ///                  0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
360    /// ```
361    #[must_use]
362    #[inline]
363    pub const fn into_inner(self) -> [u8; 16] {
364        self.0
365    }
366
367    /// Returns the bytes of the UUID.
368    ///
369    /// # Examples
370    ///
371    /// ```rust
372    /// use bare_types::net::Uuid;
373    ///
374    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
375    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
376    /// assert_eq!(uuid.bytes(), [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
377    ///                          0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
378    /// ```
379    #[must_use]
380    #[inline]
381    pub const fn bytes(&self) -> [u8; 16] {
382        self.0
383    }
384
385    /// Returns `true` if this is a nil UUID.
386    ///
387    /// The nil UUID is 00000000-0000-0000-0000-000000000000.
388    ///
389    /// # Examples
390    ///
391    /// ```rust
392    /// use bare_types::net::Uuid;
393    ///
394    /// assert!(Uuid::nil().is_nil());
395    /// ```
396    #[must_use]
397    #[inline]
398    pub fn is_nil(&self) -> bool {
399        self.0.iter().all(|&b| b == 0)
400    }
401
402    /// Returns the version of the UUID.
403    ///
404    /// Returns `None` if the UUID is not a valid RFC 4122 UUID.
405    ///
406    /// # Examples
407    ///
408    /// ```rust
409    /// use bare_types::net::Uuid;
410    ///
411    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
412    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
413    /// assert_eq!(uuid.version(), None);
414    /// ```
415    #[must_use]
416    #[inline]
417    pub fn version(&self) -> Option<u8> {
418        let version = self.0[6] >> 4;
419        if (1..=5).contains(&version) {
420            Some(version)
421        } else {
422            None
423        }
424    }
425
426    /// Returns the variant of the UUID.
427    ///
428    /// Returns `None` if the UUID is not a valid RFC 4122 UUID.
429    ///
430    /// # Examples
431    ///
432    /// ```rust
433    /// use bare_types::net::{Uuid, UuidVariant};
434    ///
435    /// let uuid = Uuid::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
436    ///                        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
437    /// assert_eq!(uuid.variant(), Some(UuidVariant::Rfc4122));
438    /// ```
439    #[must_use]
440    #[inline]
441    pub const fn variant(&self) -> Option<UuidVariant> {
442        let variant = self.0[8] >> 6;
443        match variant {
444            0b00 => Some(UuidVariant::Ncs),
445            0b10 => Some(UuidVariant::Rfc4122),
446            0b110 => Some(UuidVariant::Microsoft),
447            0b111 => Some(UuidVariant::Future),
448            _ => None,
449        }
450    }
451}
452
453/// UUID variant.
454#[derive(Debug, Clone, Copy, PartialEq, Eq)]
455#[non_exhaustive]
456pub enum UuidVariant {
457    /// NCS backward compatibility
458    Ncs,
459    /// RFC 4122
460    Rfc4122,
461    /// Microsoft GUID
462    Microsoft,
463    /// Future
464    Future,
465}
466
467impl TryFrom<&[u8]> for Uuid {
468    type Error = UuidError;
469
470    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
471        Self::from_bytes(bytes)
472    }
473}
474
475impl TryFrom<&str> for Uuid {
476    type Error = UuidError;
477
478    fn try_from(s: &str) -> Result<Self, Self::Error> {
479        Self::from_str(s)
480    }
481}
482
483impl From<Uuid> for [u8; 16] {
484    fn from(uuid: Uuid) -> Self {
485        uuid.0
486    }
487}
488
489impl From<[u8; 16]> for Uuid {
490    fn from(bytes: [u8; 16]) -> Self {
491        Self(bytes)
492    }
493}
494
495impl FromStr for Uuid {
496    type Err = UuidError;
497
498    fn from_str(s: &str) -> Result<Self, Self::Err> {
499        Self::from_str(s)
500    }
501}
502
503impl fmt::Display for Uuid {
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        write!(
506            f,
507            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
508            self.0[0],
509            self.0[1],
510            self.0[2],
511            self.0[3],
512            self.0[4],
513            self.0[5],
514            self.0[6],
515            self.0[7],
516            self.0[8],
517            self.0[9],
518            self.0[10],
519            self.0[11],
520            self.0[12],
521            self.0[13],
522            self.0[14],
523            self.0[15]
524        )
525    }
526}
527
528#[cfg(test)]
529mod tests {
530    use super::*;
531
532    #[test]
533    fn test_new_valid_uuid() {
534        let uuid = Uuid::new([
535            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
536            0xee, 0xff,
537        ]);
538        assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
539    }
540
541    #[test]
542    fn test_from_bytes_valid() {
543        let bytes = vec![
544            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
545            0xee, 0xff,
546        ];
547        assert!(Uuid::from_bytes(&bytes).is_ok());
548    }
549
550    #[test]
551    fn test_from_bytes_invalid_length() {
552        let bytes = vec![0x00, 0x11, 0x22];
553        assert_eq!(Uuid::from_bytes(&bytes), Err(UuidError::InvalidLength(3)));
554    }
555
556    #[test]
557    fn test_from_str_valid() {
558        assert!(Uuid::from_str("00112233-4455-6677-8899-aabbccddeeff").is_ok());
559        assert!(Uuid::from_str("00000000-0000-0000-0000-000000000000").is_ok());
560        assert!(Uuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").is_ok());
561    }
562
563    #[test]
564    fn test_from_str_invalid_format() {
565        assert_eq!(
566            Uuid::from_str("00112233-4455-6677-8899-aabbccddeef"),
567            Err(UuidError::InvalidFormat)
568        );
569        assert_eq!(
570            Uuid::from_str("00112233-4455-6677-8899-aabbccddeeff-"),
571            Err(UuidError::InvalidFormat)
572        );
573    }
574
575    #[test]
576    fn test_from_str_invalid_char() {
577        assert_eq!(
578            Uuid::from_str("00112233-4455-6677-8899-aabbccddeegg"),
579            Err(UuidError::InvalidChar('g'))
580        );
581        assert_eq!(
582            Uuid::from_str("00112233-4455-6677-8899-aabbccddeeGG"),
583            Err(UuidError::InvalidChar('G'))
584        );
585    }
586
587    #[test]
588    fn test_nil() {
589        let uuid = Uuid::nil();
590        assert!(uuid.is_nil());
591        assert_eq!(uuid.as_str(), "00000000-0000-0000-0000-000000000000");
592    }
593
594    #[test]
595    fn test_as_str() {
596        let uuid = Uuid::new([
597            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
598            0xee, 0xff,
599        ]);
600        assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
601    }
602
603    #[test]
604    fn test_as_str_upper() {
605        let uuid = Uuid::new([
606            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
607            0xee, 0xff,
608        ]);
609        assert_eq!(uuid.as_str_upper(), "00112233-4455-6677-8899-AABBCCDDEEFF");
610    }
611
612    #[test]
613    fn test_as_inner() {
614        let uuid = Uuid::new([
615            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
616            0xee, 0xff,
617        ]);
618        let bytes = uuid.as_inner();
619        assert_eq!(
620            bytes,
621            &[
622                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
623                0xee, 0xff
624            ]
625        );
626    }
627
628    #[test]
629    fn test_into_inner() {
630        let uuid = Uuid::new([
631            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
632            0xee, 0xff,
633        ]);
634        let bytes = uuid.into_inner();
635        assert_eq!(
636            bytes,
637            [
638                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
639                0xee, 0xff
640            ]
641        );
642    }
643
644    #[test]
645    fn test_bytes() {
646        let uuid = Uuid::new([
647            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
648            0xee, 0xff,
649        ]);
650        assert_eq!(
651            uuid.bytes(),
652            [
653                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
654                0xee, 0xff
655            ]
656        );
657    }
658
659    #[test]
660    fn test_is_nil() {
661        assert!(Uuid::nil().is_nil());
662        let uuid = Uuid::new([
663            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
664            0xee, 0xff,
665        ]);
666        assert!(!uuid.is_nil());
667    }
668
669    #[test]
670    fn test_version() {
671        let uuid = Uuid::new([
672            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
673            0xee, 0xff,
674        ]);
675        assert_eq!(uuid.version(), None);
676    }
677
678    #[test]
679    fn test_variant() {
680        let uuid = Uuid::new([
681            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
682            0xee, 0xff,
683        ]);
684        assert_eq!(uuid.variant(), Some(UuidVariant::Rfc4122));
685    }
686
687    #[test]
688    fn test_try_from_bytes() {
689        let bytes = vec![
690            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
691            0xee, 0xff,
692        ];
693        let uuid = Uuid::try_from(bytes.as_slice()).unwrap();
694        assert_eq!(
695            uuid.bytes(),
696            [
697                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
698                0xee, 0xff
699            ]
700        );
701    }
702
703    #[test]
704    fn test_try_from_str() {
705        let uuid = Uuid::try_from("00112233-4455-6677-8899-aabbccddeeff").unwrap();
706        assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
707    }
708
709    #[test]
710    fn test_from_uuid_to_array() {
711        let uuid = Uuid::new([
712            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
713            0xee, 0xff,
714        ]);
715        let bytes: [u8; 16] = uuid.into();
716        assert_eq!(
717            bytes,
718            [
719                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
720                0xee, 0xff
721            ]
722        );
723    }
724
725    #[test]
726    fn test_from_array_to_uuid() {
727        let bytes = [
728            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
729            0xee, 0xff,
730        ];
731        let uuid: Uuid = bytes.into();
732        assert_eq!(uuid.bytes(), bytes);
733    }
734
735    #[test]
736    fn test_from_str() {
737        let uuid: Uuid = "00112233-4455-6677-8899-aabbccddeeff".parse().unwrap();
738        assert_eq!(uuid.as_str(), "00112233-4455-6677-8899-aabbccddeeff");
739    }
740
741    #[test]
742    fn test_from_str_invalid() {
743        assert!(
744            "00112233-4455-6677-8899-aabbccddeef"
745                .parse::<Uuid>()
746                .is_err()
747        );
748        assert!(
749            "00112233-4455-6677-8899-aabbccddeeg!p"
750                .parse::<Uuid>()
751                .is_err()
752        );
753    }
754
755    #[test]
756    fn test_display() {
757        let uuid = Uuid::new([
758            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
759            0xee, 0xff,
760        ]);
761        assert_eq!(format!("{uuid}"), "00112233-4455-6677-8899-aabbccddeeff");
762    }
763
764    #[test]
765    fn test_equality() {
766        let uuid1 = Uuid::new([
767            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
768            0xee, 0xff,
769        ]);
770        let uuid2 = Uuid::new([
771            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
772            0xee, 0xff,
773        ]);
774        let uuid3 = Uuid::new([
775            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
776            0xee, 0xfe,
777        ]);
778
779        assert_eq!(uuid1, uuid2);
780        assert_ne!(uuid1, uuid3);
781    }
782
783    #[test]
784    fn test_ordering() {
785        let uuid1 = Uuid::new([
786            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
787            0xee, 0xfe,
788        ]);
789        let uuid2 = Uuid::new([
790            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
791            0xee, 0xff,
792        ]);
793
794        assert!(uuid1 < uuid2);
795    }
796
797    #[test]
798    fn test_clone() {
799        let uuid = Uuid::new([
800            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
801            0xee, 0xff,
802        ]);
803        let uuid2 = uuid.clone();
804        assert_eq!(uuid, uuid2);
805    }
806
807    #[test]
808    fn test_error_display() {
809        assert_eq!(
810            format!("{}", UuidError::InvalidLength(3)),
811            "UUID must be 16 bytes (got 3)"
812        );
813        assert_eq!(
814            format!("{}", UuidError::InvalidFormat),
815            "UUID must be in format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
816        );
817        assert_eq!(
818            format!("{}", UuidError::InvalidChar('g')),
819            "UUID contains invalid character 'g'"
820        );
821    }
822
823    #[test]
824    fn test_hash() {
825        use core::hash::Hash;
826        use core::hash::Hasher;
827
828        #[derive(Default)]
829        struct SimpleHasher(u64);
830
831        impl Hasher for SimpleHasher {
832            fn finish(&self) -> u64 {
833                self.0
834            }
835
836            fn write(&mut self, bytes: &[u8]) {
837                for byte in bytes {
838                    self.0 = self.0.wrapping_mul(31).wrapping_add(*byte as u64);
839                }
840            }
841        }
842
843        let uuid1 = Uuid::new([
844            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
845            0xee, 0xff,
846        ]);
847        let uuid2 = Uuid::new([
848            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
849            0xee, 0xff,
850        ]);
851        let uuid3 = Uuid::new([
852            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
853            0xee, 0xfe,
854        ]);
855
856        let mut hasher1 = SimpleHasher::default();
857        let mut hasher2 = SimpleHasher::default();
858        let mut hasher3 = SimpleHasher::default();
859
860        uuid1.hash(&mut hasher1);
861        uuid2.hash(&mut hasher2);
862        uuid3.hash(&mut hasher3);
863
864        assert_eq!(hasher1.finish(), hasher2.finish());
865        assert_ne!(hasher1.finish(), hasher3.finish());
866    }
867
868    #[test]
869    fn test_debug() {
870        let uuid = Uuid::new([
871            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
872            0xee, 0xff,
873        ]);
874        assert_eq!(
875            format!("{:?}", uuid),
876            "Uuid([0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255])"
877        );
878    }
879
880    #[test]
881    fn test_from_into_inner_roundtrip() {
882        let uuid = Uuid::new([
883            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
884            0xee, 0xff,
885        ]);
886        let bytes = uuid.into_inner();
887        let uuid2 = Uuid::new(bytes);
888        assert_eq!(
889            uuid2.bytes(),
890            [
891                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
892                0xee, 0xff
893            ]
894        );
895    }
896}