1#![doc = include_str!("../README.md")]
2
3use core::str::FromStr;
4
5pub mod diesel_impls;
6mod redis;
7
8#[repr(transparent)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(
11 feature = "diesel",
12 derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
13)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "diesel", diesel(sql_type = crate::diesel_impls::Uuid))]
16pub struct Uuid(uuid::Uuid);
29
30impl Uuid {
31 #[must_use]
32 pub fn new_v4() -> Self {
42 Self(uuid::Uuid::new_v4())
43 }
44
45 #[must_use]
46 pub fn utc_v7() -> Self {
56 let utc_now = ::chrono::Utc::now();
57 ::uuid::Uuid::new_v7(::uuid::Timestamp::from_unix_time(
58 u64::try_from(utc_now.timestamp()).expect("Time went backwards"),
59 utc_now.timestamp_subsec_nanos(),
60 0,
61 12,
62 ))
63 .into()
64 }
65}
66
67impl Default for Uuid {
68 fn default() -> Self {
69 Self(uuid::Uuid::nil())
70 }
71}
72
73impl FromStr for Uuid {
74 type Err = uuid::Error;
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 Ok(Self(uuid::Uuid::from_str(s)?))
78 }
79}
80
81impl From<uuid::Uuid> for Uuid {
82 fn from(uuid: uuid::Uuid) -> Self {
83 Self(uuid)
84 }
85}
86
87impl From<Uuid> for uuid::Uuid {
88 fn from(uuid: Uuid) -> Self {
89 uuid.0
90 }
91}
92
93impl From<[u8; 16]> for Uuid {
94 fn from(bytes: [u8; 16]) -> Self {
95 Self(uuid::Uuid::from_bytes(bytes))
96 }
97}
98
99impl From<Uuid> for [u8; 16] {
100 fn from(uuid: Uuid) -> Self {
101 *uuid.0.as_bytes()
102 }
103}
104
105impl<'a> From<&'a [u8; 16]> for Uuid {
106 fn from(bytes: &'a [u8; 16]) -> Self {
107 Self(uuid::Uuid::from_bytes(*bytes))
108 }
109}
110
111impl AsRef<uuid::Uuid> for Uuid {
112 fn as_ref(&self) -> &uuid::Uuid {
113 &self.0
114 }
115}
116
117impl AsMut<uuid::Uuid> for Uuid {
118 fn as_mut(&mut self) -> &mut uuid::Uuid {
119 &mut self.0
120 }
121}
122
123impl AsRef<[u8; 16]> for Uuid {
124 fn as_ref(&self) -> &[u8; 16] {
125 self.0.as_bytes()
126 }
127}
128
129impl core::ops::Deref for Uuid {
130 type Target = uuid::Uuid;
131
132 fn deref(&self) -> &Self::Target {
133 &self.0
134 }
135}
136
137impl core::ops::DerefMut for Uuid {
138 fn deref_mut(&mut self) -> &mut Self::Target {
139 &mut self.0
140 }
141}
142
143impl core::fmt::Display for Uuid {
144 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
145 self.0.fmt(f)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use std::cmp::Ordering;
153 use std::collections::HashSet;
154 use std::str::FromStr;
155
156 #[test]
157 fn test_default() {
158 let uuid = Uuid::default();
159 assert_eq!(uuid.0, uuid::Uuid::nil());
160 assert_eq!(uuid.to_string(), "00000000-0000-0000-0000-000000000000");
161 }
162
163 #[test]
164 fn test_from_str() {
165 let s = "67e55044-10b1-426f-9247-bb680e5fe0c8";
166 let uuid = Uuid::from_str(s).unwrap();
167 assert_eq!(uuid.to_string(), s);
168
169 let invalid = "invalid-uuid";
170 assert!(Uuid::from_str(invalid).is_err());
171 }
172
173 #[test]
174 fn test_from_conversions() {
175 let inner = uuid::Uuid::new_v4();
176 let wrapper: Uuid = inner.into();
177 assert_eq!(wrapper.0, inner);
178
179 let back: uuid::Uuid = wrapper.into();
180 assert_eq!(back, inner);
181
182 let bytes = [0u8; 16];
183 let from_bytes: Uuid = bytes.into();
184 assert_eq!(from_bytes.0, uuid::Uuid::nil());
185
186 let bytes_back: [u8; 16] = from_bytes.into();
187 assert_eq!(bytes_back, bytes);
188
189 let bytes_ref = &[0u8; 16];
190 let from_bytes_ref: Uuid = bytes_ref.into();
191 assert_eq!(from_bytes_ref.0, uuid::Uuid::nil());
192 }
193
194 #[test]
195 fn test_as_ref_as_mut() {
196 let mut uuid = Uuid::new_v4();
197
198 let r: &uuid::Uuid = uuid.as_ref();
199 assert_eq!(*r, uuid.0);
200
201 let bytes_ref: &[u8; 16] = uuid.as_ref();
202 assert_eq!(bytes_ref, uuid.0.as_bytes());
203
204 let m: &mut uuid::Uuid = uuid.as_mut();
205 *m = uuid::Uuid::nil();
207 assert_eq!(uuid.0, uuid::Uuid::nil());
208 }
209
210 #[test]
211 fn test_deref_deref_mut() {
212 let mut uuid = Uuid::new_v4();
213
214 assert_eq!(uuid.get_version(), Some(uuid::Version::Random));
216
217 *uuid = uuid::Uuid::nil();
219 assert!(uuid.is_nil());
220 }
221
222 #[test]
223 fn test_display() {
224 let s = "67e55044-10b1-426f-9247-bb680e5fe0c8";
225 let uuid = Uuid::from_str(s).unwrap();
226 assert_eq!(format!("{uuid}"), s);
227 }
228
229 #[test]
230 fn test_standard_traits() {
231 let uuid1 = Uuid::new_v4();
232 let uuid2 = Clone::clone(&uuid1); let uuid3 = uuid1; assert_eq!(uuid1, uuid2); assert_eq!(uuid1, uuid3); assert!(uuid1 == uuid2); let mut set = HashSet::new();
240 set.insert(uuid1); assert!(set.contains(&uuid2));
242 }
243
244 #[test]
245 fn test_ord() {
246 let u1 = Uuid::default(); let u2 = Uuid::new_v4(); assert_eq!(u1.cmp(&u2), Ordering::Less); assert!(u1 < u2); }
252
253 #[test]
254 fn test_new_constructors() {
255 let v4 = Uuid::new_v4();
256 assert_eq!(v4.get_version(), Some(uuid::Version::Random));
257
258 let v7 = Uuid::utc_v7();
259 assert!(!v7.is_nil());
262 }
263}