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