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}