Skip to main content

reifydb_type/value/uuid/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::{
5	cmp::Ordering,
6	fmt,
7	fmt::{Display, Formatter},
8	ops::Deref,
9};
10
11use ::uuid::{Builder, Uuid as StdUuid};
12use reifydb_runtime::context::{clock::Clock, rng::Rng};
13use serde::{Deserialize, Serialize};
14use uuid::Uuid;
15
16pub mod parse;
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<'_>) -> 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 using the provided clock and RNG.
88	pub fn generate(clock: &Clock, rng: &Rng) -> Self {
89		let millis = clock.now_millis();
90		let random_bytes = rng.bytes_10();
91		Uuid7(Builder::from_unix_timestamp_millis(millis, &random_bytes).into_uuid())
92	}
93}
94
95impl Deref for Uuid7 {
96	type Target = StdUuid;
97
98	fn deref(&self) -> &Self::Target {
99		&self.0
100	}
101}
102
103impl PartialOrd for Uuid7 {
104	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
105		Some(self.cmp(other))
106	}
107}
108
109impl Ord for Uuid7 {
110	fn cmp(&self, other: &Self) -> Ordering {
111		self.0.as_bytes().cmp(other.0.as_bytes())
112	}
113}
114
115impl From<StdUuid> for Uuid7 {
116	fn from(uuid: StdUuid) -> Self {
117		debug_assert!(uuid.get_version_num() == 7 || uuid.get_version_num() == 0);
118		Uuid7(uuid)
119	}
120}
121
122impl From<Uuid7> for StdUuid {
123	fn from(uuid7: Uuid7) -> Self {
124		uuid7.0
125	}
126}
127
128impl Display for Uuid7 {
129	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
130		write!(f, "{}", self.0)
131	}
132}
133
134#[cfg(test)]
135#[allow(clippy::approx_constant)]
136pub mod tests {
137	use reifydb_runtime::context::clock::MockClock;
138
139	use super::*;
140
141	fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
142		let mock = MockClock::from_millis(1000);
143		let clock = Clock::Mock(mock.clone());
144		let rng = Rng::seeded(42);
145		(mock, clock, rng)
146	}
147
148	#[test]
149	fn test_uuid4_generate() {
150		let uuid4 = Uuid4::generate();
151		assert_eq!(uuid4.get_version_num(), 4);
152	}
153
154	#[test]
155	fn test_uuid4_equality() {
156		let std_uuid = StdUuid::new_v4();
157		let uuid4_a = Uuid4(std_uuid);
158		let uuid4_b = Uuid4(std_uuid);
159		let uuid4_c = Uuid4::generate();
160
161		assert_eq!(uuid4_a, uuid4_b);
162		assert_ne!(uuid4_a, uuid4_c);
163	}
164
165	#[test]
166	fn test_uuid4_ordering() {
167		let uuid4_a = Uuid4::generate();
168		let uuid4_b = Uuid4::generate();
169
170		let cmp1 = uuid4_a.cmp(&uuid4_b);
171		let cmp2 = uuid4_a.cmp(&uuid4_b);
172		assert_eq!(cmp1, cmp2);
173
174		assert_eq!(uuid4_a.cmp(&uuid4_a), Ordering::Equal);
175	}
176
177	#[test]
178	fn test_uuid4_display() {
179		let std_uuid = StdUuid::new_v4();
180		let uuid4 = Uuid4(std_uuid);
181
182		assert_eq!(format!("{}", uuid4), format!("{}", std_uuid));
183	}
184
185	#[test]
186	fn test_uuid7_generate() {
187		let (_, clock, rng) = test_clock_and_rng();
188		let uuid7 = Uuid7::generate(&clock, &rng);
189		assert_eq!(uuid7.get_version_num(), 7);
190	}
191
192	#[test]
193	fn test_uuid7_equality() {
194		let (mock, clock, rng) = test_clock_and_rng();
195		let uuid7_a = Uuid7::generate(&clock, &rng);
196		let uuid7_b = Uuid7(uuid7_a.0);
197		mock.advance_millis(1);
198		let uuid7_c = Uuid7::generate(&clock, &rng);
199
200		assert_eq!(uuid7_a, uuid7_b);
201		assert_ne!(uuid7_a, uuid7_c);
202	}
203
204	#[test]
205	fn test_uuid7_ordering() {
206		let (mock, clock, rng) = test_clock_and_rng();
207		let uuid7_a = Uuid7::generate(&clock, &rng);
208		mock.advance_millis(1);
209		let uuid7_b = Uuid7::generate(&clock, &rng);
210
211		let cmp1 = uuid7_a.cmp(&uuid7_b);
212		let cmp2 = uuid7_a.cmp(&uuid7_b);
213		assert_eq!(cmp1, cmp2);
214
215		assert_eq!(uuid7_a.cmp(&uuid7_a), Ordering::Equal);
216	}
217
218	#[test]
219	fn test_uuid7_display() {
220		let (_, clock, rng) = test_clock_and_rng();
221		let uuid7 = Uuid7::generate(&clock, &rng);
222		let display = format!("{}", uuid7);
223		assert!(!display.is_empty());
224	}
225
226	#[test]
227	fn test_uuid7_timestamp_ordering() {
228		let (mock, clock, rng) = test_clock_and_rng();
229		let uuid7_first = Uuid7::generate(&clock, &rng);
230		mock.advance_millis(1);
231		let uuid7_second = Uuid7::generate(&clock, &rng);
232
233		assert!(uuid7_first < uuid7_second);
234	}
235}