reifydb_type/value/uuid/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::{
5	cmp::Ordering,
6	fmt::{Display, Formatter},
7	ops::Deref,
8};
9
10use ::uuid::Uuid as StdUuid;
11use serde::{Deserialize, Serialize};
12use uuid::Uuid;
13
14pub mod parse;
15
16pub use parse::{parse_uuid4, parse_uuid7};
17
18/// A UUID version 4 (random) wrapper type
19#[repr(transparent)]
20#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
21pub struct Uuid4(pub StdUuid);
22
23impl Uuid4 {
24	/// Generate a new random UUID v4
25	pub fn generate() -> Self {
26		Uuid4(StdUuid::new_v4())
27	}
28}
29
30impl Default for Uuid4 {
31	fn default() -> Self {
32		Self(Uuid::nil())
33	}
34}
35
36impl Deref for Uuid4 {
37	type Target = StdUuid;
38
39	fn deref(&self) -> &Self::Target {
40		&self.0
41	}
42}
43
44impl PartialOrd for Uuid4 {
45	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
46		Some(self.cmp(other))
47	}
48}
49
50impl Ord for Uuid4 {
51	fn cmp(&self, other: &Self) -> Ordering {
52		self.0.as_bytes().cmp(other.0.as_bytes())
53	}
54}
55
56impl From<StdUuid> for Uuid4 {
57	fn from(uuid: StdUuid) -> Self {
58		debug_assert!(uuid.get_version_num() == 4 || uuid.get_version_num() == 0);
59		Uuid4(uuid)
60	}
61}
62
63impl From<Uuid4> for StdUuid {
64	fn from(uuid4: Uuid4) -> Self {
65		uuid4.0
66	}
67}
68
69impl Display for Uuid4 {
70	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71		write!(f, "{}", self.0)
72	}
73}
74
75/// A UUID version 7 (timestamp-based) wrapper type
76#[repr(transparent)]
77#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
78pub struct Uuid7(pub StdUuid);
79
80impl Default for Uuid7 {
81	fn default() -> Self {
82		Self(Uuid::nil())
83	}
84}
85
86impl Uuid7 {
87	/// Generate a new timestamp-based UUID v7
88	pub fn generate() -> Self {
89		Uuid7(StdUuid::now_v7())
90	}
91}
92
93impl Deref for Uuid7 {
94	type Target = StdUuid;
95
96	fn deref(&self) -> &Self::Target {
97		&self.0
98	}
99}
100
101impl PartialOrd for Uuid7 {
102	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103		Some(self.cmp(other))
104	}
105}
106
107impl Ord for Uuid7 {
108	fn cmp(&self, other: &Self) -> Ordering {
109		self.0.as_bytes().cmp(other.0.as_bytes())
110	}
111}
112
113impl From<StdUuid> for Uuid7 {
114	fn from(uuid: StdUuid) -> Self {
115		debug_assert!(uuid.get_version_num() == 7 || uuid.get_version_num() == 0);
116		Uuid7(uuid)
117	}
118}
119
120impl From<Uuid7> for StdUuid {
121	fn from(uuid7: Uuid7) -> Self {
122		uuid7.0
123	}
124}
125
126impl Display for Uuid7 {
127	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
128		write!(f, "{}", self.0)
129	}
130}
131
132#[cfg(test)]
133#[allow(clippy::approx_constant)]
134mod tests {
135	use std::time::Duration;
136
137	use tokio::time::sleep;
138
139	use super::*;
140
141	#[test]
142	fn test_uuid4_generate() {
143		let uuid4 = Uuid4::generate();
144		assert_eq!(uuid4.get_version_num(), 4);
145	}
146
147	#[test]
148	fn test_uuid4_equality() {
149		let std_uuid = StdUuid::new_v4();
150		let uuid4_a = Uuid4(std_uuid);
151		let uuid4_b = Uuid4(std_uuid);
152		let uuid4_c = Uuid4::generate();
153
154		assert_eq!(uuid4_a, uuid4_b);
155		assert_ne!(uuid4_a, uuid4_c);
156	}
157
158	#[test]
159	fn test_uuid4_ordering() {
160		let uuid4_a = Uuid4::generate();
161		let uuid4_b = Uuid4::generate();
162
163		// Should be consistently ordered
164		let cmp1 = uuid4_a.cmp(&uuid4_b);
165		let cmp2 = uuid4_a.cmp(&uuid4_b);
166		assert_eq!(cmp1, cmp2);
167
168		// Self comparison should be Equal
169		assert_eq!(uuid4_a.cmp(&uuid4_a), Ordering::Equal);
170	}
171
172	#[test]
173	fn test_uuid4_display() {
174		let std_uuid = StdUuid::new_v4();
175		let uuid4 = Uuid4(std_uuid);
176
177		assert_eq!(format!("{}", uuid4), format!("{}", std_uuid));
178	}
179
180	#[test]
181	fn test_uuid7_generate() {
182		let uuid7 = Uuid7::generate();
183		assert_eq!(uuid7.get_version_num(), 7);
184	}
185
186	#[test]
187	fn test_uuid7_equality() {
188		let std_uuid = StdUuid::now_v7();
189		let uuid7_a = Uuid7(std_uuid);
190		let uuid7_b = Uuid7(std_uuid);
191		let uuid7_c = Uuid7::generate();
192
193		assert_eq!(uuid7_a, uuid7_b);
194		assert_ne!(uuid7_a, uuid7_c);
195	}
196
197	#[test]
198	fn test_uuid7_ordering() {
199		let uuid7_a = Uuid7::generate();
200		let uuid7_b = Uuid7::generate();
201
202		// Should be consistently ordered
203		let cmp1 = uuid7_a.cmp(&uuid7_b);
204		let cmp2 = uuid7_a.cmp(&uuid7_b);
205		assert_eq!(cmp1, cmp2);
206
207		// Self comparison should be Equal
208		assert_eq!(uuid7_a.cmp(&uuid7_a), Ordering::Equal);
209	}
210
211	#[test]
212	fn test_uuid7_display() {
213		let std_uuid = StdUuid::now_v7();
214		let uuid7 = Uuid7(std_uuid);
215
216		assert_eq!(format!("{}", uuid7), format!("{}", std_uuid));
217	}
218
219	#[tokio::test]
220	async fn test_uuid7_timestamp_ordering() {
221		// UUID v7 should have timestamp-based ordering for UUIDs
222		// generated close in time
223		let uuid7_first = Uuid7::generate();
224		sleep(Duration::from_millis(1)).await;
225		let uuid7_second = Uuid7::generate();
226
227		// The first UUID should be less than the second (in most cases
228		// due to timestamp) Note: This test might occasionally fail
229		// due to timing, but it demonstrates the concept
230		assert!(uuid7_first <= uuid7_second);
231	}
232}