Coverage Report

Created: 2026-03-23 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/uuid-1.19.0/src/non_nil.rs
Line
Count
Source
1
//! A wrapper type for nil UUIDs that provides a more memory-efficient
2
//! `Option<NonNilUuid>` representation.
3
4
use std::{fmt, num::NonZeroU128};
5
6
use crate::{
7
    error::{Error, ErrorKind},
8
    Uuid,
9
};
10
11
/// A UUID that is guaranteed not to be the [nil UUID](https://www.ietf.org/rfc/rfc9562.html#name-nil-uuid).
12
///
13
/// This is useful for representing optional UUIDs more efficiently, as `Option<NonNilUuid>`
14
/// takes up the same space as `Uuid`.
15
///
16
/// Note that `Uuid`s created by the following methods are guaranteed to be non-nil:
17
///
18
/// - [`Uuid::new_v1`]
19
/// - [`Uuid::now_v1`]
20
/// - [`Uuid::new_v3`]
21
/// - [`Uuid::new_v4`]
22
/// - [`Uuid::new_v5`]
23
/// - [`Uuid::new_v6`]
24
/// - [`Uuid::now_v6`]
25
/// - [`Uuid::new_v7`]
26
/// - [`Uuid::now_v7`]
27
/// - [`Uuid::new_v8`]
28
///
29
/// # ABI
30
///
31
/// The `NonNilUuid` type does not yet have a stable ABI. Its representation or alignment
32
/// may change. It is currently only guaranteed that `NonNilUuid` and `Option<NonNilUuid>`
33
/// are the same size as `Uuid`.
34
#[repr(transparent)]
35
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
36
pub struct NonNilUuid(NonZeroU128);
37
38
impl fmt::Debug for NonNilUuid {
39
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40
0
        fmt::Debug::fmt(&Uuid::from(*self), f)
41
0
    }
42
}
43
44
impl fmt::Display for NonNilUuid {
45
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46
0
        fmt::Display::fmt(&Uuid::from(*self), f)
47
0
    }
48
}
49
50
impl PartialEq<Uuid> for NonNilUuid {
51
0
    fn eq(&self, other: &Uuid) -> bool {
52
0
        self.get() == *other
53
0
    }
54
}
55
56
impl PartialEq<NonNilUuid> for Uuid {
57
0
    fn eq(&self, other: &NonNilUuid) -> bool {
58
0
        *self == other.get()
59
0
    }
60
}
61
62
impl NonNilUuid {
63
    /// Creates a non-nil UUID if the value is non-nil.
64
0
    pub const fn new(uuid: Uuid) -> Option<Self> {
65
0
        match NonZeroU128::new(uuid.as_u128()) {
66
0
            Some(non_nil) => Some(NonNilUuid(non_nil)),
67
0
            None => None,
68
        }
69
0
    }
70
71
    /// Creates a non-nil without checking whether the value is non-nil. This results in undefined behavior if the value is nil.
72
    ///
73
    /// # Safety
74
    ///
75
    /// The value must not be nil.
76
0
    pub const unsafe fn new_unchecked(uuid: Uuid) -> Self {
77
0
        NonNilUuid(unsafe { NonZeroU128::new_unchecked(uuid.as_u128()) })
78
0
    }
79
80
    /// Get the underlying [`Uuid`] value.
81
    #[inline]
82
0
    pub const fn get(self) -> Uuid {
83
0
        Uuid::from_u128(self.0.get())
84
0
    }
85
}
86
87
impl From<NonNilUuid> for Uuid {
88
    /// Converts a [`NonNilUuid`] back into a [`Uuid`].
89
    ///
90
    /// # Examples
91
    /// ```
92
    /// # use uuid::{NonNilUuid, Uuid};
93
    /// let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
94
    /// let non_nil = NonNilUuid::try_from(uuid).unwrap();
95
    /// let uuid_again = Uuid::from(non_nil);
96
    ///
97
    /// assert_eq!(uuid, uuid_again);
98
    /// ```
99
0
    fn from(non_nil: NonNilUuid) -> Self {
100
0
        Uuid::from_u128(non_nil.0.get())
101
0
    }
102
}
103
104
impl TryFrom<Uuid> for NonNilUuid {
105
    type Error = Error;
106
107
    /// Attempts to convert a [`Uuid`] into a [`NonNilUuid`].
108
    ///
109
    /// # Examples
110
    /// ```
111
    /// # use uuid::{NonNilUuid, Uuid};
112
    /// let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
113
    /// let non_nil = NonNilUuid::try_from(uuid).unwrap();
114
    /// ```
115
0
    fn try_from(uuid: Uuid) -> Result<Self, Self::Error> {
116
0
        NonZeroU128::new(uuid.as_u128())
117
0
            .map(Self)
118
0
            .ok_or(Error(ErrorKind::Nil))
119
0
    }
120
}
121
122
#[cfg(test)]
123
mod tests {
124
    use super::*;
125
126
    #[test]
127
    fn test_non_nil_with_option_size() {
128
        assert_eq!(
129
            std::mem::size_of::<Option<NonNilUuid>>(),
130
            std::mem::size_of::<Uuid>()
131
        );
132
    }
133
134
    #[test]
135
    fn test_non_nil() {
136
        let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
137
138
        assert_eq!(Uuid::from(NonNilUuid::try_from(uuid).unwrap()), uuid);
139
        assert_eq!(NonNilUuid::new(uuid).unwrap(), uuid);
140
        assert_eq!(unsafe { NonNilUuid::new_unchecked(uuid) }, uuid);
141
142
        assert!(NonNilUuid::try_from(Uuid::nil()).is_err());
143
        assert!(NonNilUuid::new(Uuid::nil()).is_none());
144
    }
145
146
    #[test]
147
    fn test_non_nil_formatting() {
148
        let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
149
        let non_nil = NonNilUuid::try_from(uuid).unwrap();
150
151
        assert_eq!(format!("{uuid}"), format!("{non_nil}"));
152
        assert_eq!(format!("{uuid:?}"), format!("{non_nil:?}"));
153
    }
154
}