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 super::*;
136
137	#[test]
138	fn test_uuid4_generate() {
139		let uuid4 = Uuid4::generate();
140		assert_eq!(uuid4.get_version_num(), 4);
141	}
142
143	#[test]
144	fn test_uuid4_equality() {
145		let std_uuid = StdUuid::new_v4();
146		let uuid4_a = Uuid4(std_uuid);
147		let uuid4_b = Uuid4(std_uuid);
148		let uuid4_c = Uuid4::generate();
149
150		assert_eq!(uuid4_a, uuid4_b);
151		assert_ne!(uuid4_a, uuid4_c);
152	}
153
154	#[test]
155	fn test_uuid4_ordering() {
156		let uuid4_a = Uuid4::generate();
157		let uuid4_b = Uuid4::generate();
158
159		// Should be consistently ordered
160		let cmp1 = uuid4_a.cmp(&uuid4_b);
161		let cmp2 = uuid4_a.cmp(&uuid4_b);
162		assert_eq!(cmp1, cmp2);
163
164		// Self comparison should be Equal
165		assert_eq!(uuid4_a.cmp(&uuid4_a), Ordering::Equal);
166	}
167
168	#[test]
169	fn test_uuid4_display() {
170		let std_uuid = StdUuid::new_v4();
171		let uuid4 = Uuid4(std_uuid);
172
173		assert_eq!(format!("{}", uuid4), format!("{}", std_uuid));
174	}
175
176	#[test]
177	fn test_uuid7_generate() {
178		let uuid7 = Uuid7::generate();
179		assert_eq!(uuid7.get_version_num(), 7);
180	}
181
182	#[test]
183	fn test_uuid7_equality() {
184		let std_uuid = StdUuid::now_v7();
185		let uuid7_a = Uuid7(std_uuid);
186		let uuid7_b = Uuid7(std_uuid);
187		let uuid7_c = Uuid7::generate();
188
189		assert_eq!(uuid7_a, uuid7_b);
190		assert_ne!(uuid7_a, uuid7_c);
191	}
192
193	#[test]
194	fn test_uuid7_ordering() {
195		let uuid7_a = Uuid7::generate();
196		let uuid7_b = Uuid7::generate();
197
198		// Should be consistently ordered
199		let cmp1 = uuid7_a.cmp(&uuid7_b);
200		let cmp2 = uuid7_a.cmp(&uuid7_b);
201		assert_eq!(cmp1, cmp2);
202
203		// Self comparison should be Equal
204		assert_eq!(uuid7_a.cmp(&uuid7_a), Ordering::Equal);
205	}
206
207	#[test]
208	fn test_uuid7_display() {
209		let std_uuid = StdUuid::now_v7();
210		let uuid7 = Uuid7(std_uuid);
211
212		assert_eq!(format!("{}", uuid7), format!("{}", std_uuid));
213	}
214
215	#[test]
216	fn test_uuid7_timestamp_ordering() {
217		// UUID v7 should have timestamp-based ordering for UUIDs
218		// generated close in time
219		let uuid7_first = Uuid7::generate();
220		std::thread::sleep(std::time::Duration::from_millis(1));
221		let uuid7_second = Uuid7::generate();
222
223		// The first UUID should be less than the second (in most cases
224		// due to timestamp) Note: This test might occasionally fail
225		// due to timing, but it demonstrates the concept
226		assert!(uuid7_first <= uuid7_second);
227	}
228}