1use std::{cmp::Ordering, fmt, num::NonZeroU128};
5
6use crate::{
7 error::{Error, ErrorKind},
8 Uuid,
9};
10
11#[repr(transparent)]
35#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
36pub struct NonNilUuid(NonZeroU128);
37
38impl fmt::Debug for NonNilUuid {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 fmt::Debug::fmt(&Uuid::from(*self), f)
41 }
42}
43
44impl fmt::Display for NonNilUuid {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 fmt::Display::fmt(&Uuid::from(*self), f)
47 }
48}
49
50impl PartialEq<Uuid> for NonNilUuid {
51 fn eq(&self, other: &Uuid) -> bool {
52 self.get() == *other
53 }
54}
55
56impl PartialEq<NonNilUuid> for Uuid {
57 fn eq(&self, other: &NonNilUuid) -> bool {
58 *self == other.get()
59 }
60}
61
62impl PartialOrd<Uuid> for NonNilUuid {
63 fn partial_cmp(&self, other: &Uuid) -> Option<Ordering> {
64 self.get().partial_cmp(other)
65 }
66}
67
68impl PartialOrd<NonNilUuid> for Uuid {
69 fn partial_cmp(&self, other: &NonNilUuid) -> Option<Ordering> {
70 self.partial_cmp(&other.get())
71 }
72}
73
74impl NonNilUuid {
75 pub const fn new(uuid: Uuid) -> Option<Self> {
77 match NonZeroU128::new(uuid.as_u128()) {
78 Some(non_nil) => Some(NonNilUuid(non_nil)),
79 None => None,
80 }
81 }
82
83 pub const unsafe fn new_unchecked(uuid: Uuid) -> Self {
89 NonNilUuid(unsafe { NonZeroU128::new_unchecked(uuid.as_u128()) })
90 }
91
92 #[inline]
94 pub const fn get(self) -> Uuid {
95 Uuid::from_u128(self.0.get())
96 }
97}
98
99impl From<NonNilUuid> for Uuid {
100 fn from(non_nil: NonNilUuid) -> Self {
112 Uuid::from_u128(non_nil.0.get())
113 }
114}
115
116impl TryFrom<Uuid> for NonNilUuid {
117 type Error = Error;
118
119 fn try_from(uuid: Uuid) -> Result<Self, Self::Error> {
128 NonZeroU128::new(uuid.as_u128())
129 .map(Self)
130 .ok_or(Error(ErrorKind::Nil))
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_non_nil_with_option_size() {
140 assert_eq!(
141 std::mem::size_of::<Option<NonNilUuid>>(),
142 std::mem::size_of::<Uuid>()
143 );
144 }
145
146 #[test]
147 fn test_non_nil() {
148 let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
149
150 assert_eq!(Uuid::from(NonNilUuid::try_from(uuid).unwrap()), uuid);
151 assert_eq!(NonNilUuid::new(uuid).unwrap(), uuid);
152 assert_eq!(unsafe { NonNilUuid::new_unchecked(uuid) }, uuid);
153
154 assert!(NonNilUuid::try_from(Uuid::nil()).is_err());
155 assert!(NonNilUuid::new(Uuid::nil()).is_none());
156 }
157
158 #[test]
159 fn test_non_nil_formatting() {
160 let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
161 let non_nil = NonNilUuid::try_from(uuid).unwrap();
162
163 assert_eq!(format!("{uuid}"), format!("{non_nil}"));
164 assert_eq!(format!("{uuid:?}"), format!("{non_nil:?}"));
165 }
166
167 #[test]
168 fn test_non_nil_ord() {
169 let uuid1 = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
170 let uuid2 = Uuid::from_u128(0x0123456789abcdef0123456789abcdf0);
171
172 let non_nil1 = NonNilUuid::try_from(uuid1).unwrap();
173 let non_nil2 = NonNilUuid::try_from(uuid2).unwrap();
174
175 assert!(non_nil1 < non_nil2);
177 assert!(non_nil2 > non_nil1);
178
179 assert!(non_nil1 < uuid2);
181 assert!(non_nil2 > uuid1);
182
183 assert!(uuid1 < non_nil2);
185 assert!(uuid2 > non_nil1);
186
187 let non_nil1_copy = NonNilUuid::try_from(uuid1).unwrap();
189 assert_eq!(non_nil1, non_nil1_copy);
190 assert!(non_nil1 <= non_nil1_copy);
191 assert!(non_nil1 >= non_nil1_copy);
192
193 assert_eq!(non_nil1, uuid1);
195 assert_eq!(uuid1, non_nil1);
196 assert!(non_nil1 >= uuid1);
197 assert!(non_nil1 <= uuid1);
198 assert!(uuid1 >= non_nil1);
199 assert!(uuid1 <= non_nil1);
200 }
201}