1use core::convert::TryFrom;
5use std::{fmt, num::NonZeroU128};
6
7use crate::{
8    error::{Error, ErrorKind},
9    Uuid,
10};
11
12#[repr(transparent)]
36#[derive(Copy, Clone, PartialEq, Eq, Hash)]
37pub struct NonNilUuid(NonZeroU128);
38
39impl fmt::Debug for NonNilUuid {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        fmt::Debug::fmt(&Uuid::from(*self), f)
42    }
43}
44
45impl fmt::Display for NonNilUuid {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        fmt::Display::fmt(&Uuid::from(*self), f)
48    }
49}
50
51impl PartialEq<Uuid> for NonNilUuid {
52    fn eq(&self, other: &Uuid) -> bool {
53        self.get() == *other
54    }
55}
56
57impl PartialEq<NonNilUuid> for Uuid {
58    fn eq(&self, other: &NonNilUuid) -> bool {
59        *self == other.get()
60    }
61}
62
63impl NonNilUuid {
64    pub const fn new(uuid: Uuid) -> Option<Self> {
66        match NonZeroU128::new(uuid.as_u128()) {
67            Some(non_nil) => Some(NonNilUuid(non_nil)),
68            None => None,
69        }
70    }
71
72    pub const unsafe fn new_unchecked(uuid: Uuid) -> Self {
78        NonNilUuid(unsafe { NonZeroU128::new_unchecked(uuid.as_u128()) })
79    }
80
81    #[inline]
83    pub const fn get(self) -> Uuid {
84        Uuid::from_u128(self.0.get())
85    }
86}
87
88impl From<NonNilUuid> for Uuid {
89    fn from(non_nil: NonNilUuid) -> Self {
102        Uuid::from_u128(non_nil.0.get())
103    }
104}
105
106impl TryFrom<Uuid> for NonNilUuid {
107    type Error = Error;
108
109    fn try_from(uuid: Uuid) -> Result<Self, Self::Error> {
119        NonZeroU128::new(uuid.as_u128())
120            .map(Self)
121            .ok_or(Error(ErrorKind::Nil))
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_non_nil_with_option_size() {
131        assert_eq!(
132            std::mem::size_of::<Option<NonNilUuid>>(),
133            std::mem::size_of::<Uuid>()
134        );
135    }
136
137    #[test]
138    fn test_non_nil() {
139        let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
140
141        assert_eq!(Uuid::from(NonNilUuid::try_from(uuid).unwrap()), uuid);
142        assert_eq!(NonNilUuid::new(uuid).unwrap(), uuid);
143        assert_eq!(unsafe { NonNilUuid::new_unchecked(uuid) }, uuid);
144
145        assert!(NonNilUuid::try_from(Uuid::nil()).is_err());
146        assert!(NonNilUuid::new(Uuid::nil()).is_none());
147    }
148
149    #[test]
150    fn test_non_nil_formatting() {
151        let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
152        let non_nil = NonNilUuid::try_from(uuid).unwrap();
153
154        assert_eq!(format!("{uuid}"), format!("{non_nil}"));
155        assert_eq!(format!("{uuid:?}"), format!("{non_nil:?}"));
156    }
157}