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