Skip to main content

reifydb_type/value/uuid/
mod.rs

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