Skip to main content

reifydb_value/value/uuid/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 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 serde::{Deserialize, Serialize};
13use uuid::Uuid;
14
15use crate::{
16	clock::{ClockNow, RandomBytes},
17	reifydb_assertions,
18};
19
20pub mod parse;
21
22#[repr(transparent)]
23#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
24pub struct Uuid4(pub StdUuid);
25
26#[cfg(feature = "host")]
27impl Uuid4 {
28	pub fn generate() -> Self {
29		Uuid4(StdUuid::new_v4())
30	}
31}
32
33impl Default for Uuid4 {
34	fn default() -> Self {
35		Self(Uuid::nil())
36	}
37}
38
39impl Deref for Uuid4 {
40	type Target = StdUuid;
41
42	fn deref(&self) -> &Self::Target {
43		&self.0
44	}
45}
46
47impl PartialOrd for Uuid4 {
48	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
49		Some(self.cmp(other))
50	}
51}
52
53impl Ord for Uuid4 {
54	fn cmp(&self, other: &Self) -> Ordering {
55		self.0.as_bytes().cmp(other.0.as_bytes())
56	}
57}
58
59impl From<StdUuid> for Uuid4 {
60	fn from(uuid: StdUuid) -> Self {
61		reifydb_assertions! {
62			assert!(uuid.get_version_num() == 4 || uuid.get_version_num() == 0);
63		}
64		Uuid4(uuid)
65	}
66}
67
68impl From<Uuid4> for StdUuid {
69	fn from(uuid4: Uuid4) -> Self {
70		uuid4.0
71	}
72}
73
74impl Display for Uuid4 {
75	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
76		write!(f, "{}", self.0)
77	}
78}
79
80#[repr(transparent)]
81#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
82pub struct Uuid7(pub StdUuid);
83
84impl Default for Uuid7 {
85	fn default() -> Self {
86		Self(Uuid::nil())
87	}
88}
89
90impl Uuid7 {
91	pub fn generate<C: ClockNow, R: RandomBytes>(clock: &C, rng: &R) -> Self {
92		let millis =
93			u64::try_from(clock.now().to_millis()).expect("system clock is never before the Unix epoch");
94		let random_bytes = rng.bytes_10();
95		Uuid7(Builder::from_unix_timestamp_millis(millis, &random_bytes).into_uuid())
96	}
97}
98
99impl Deref for Uuid7 {
100	type Target = StdUuid;
101
102	fn deref(&self) -> &Self::Target {
103		&self.0
104	}
105}
106
107impl PartialOrd for Uuid7 {
108	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
109		Some(self.cmp(other))
110	}
111}
112
113impl Ord for Uuid7 {
114	fn cmp(&self, other: &Self) -> Ordering {
115		self.0.as_bytes().cmp(other.0.as_bytes())
116	}
117}
118
119impl From<StdUuid> for Uuid7 {
120	fn from(uuid: StdUuid) -> Self {
121		reifydb_assertions! {
122			assert!(uuid.get_version_num() == 7 || uuid.get_version_num() == 0);
123		}
124		Uuid7(uuid)
125	}
126}
127
128impl From<Uuid7> for StdUuid {
129	fn from(uuid7: Uuid7) -> Self {
130		uuid7.0
131	}
132}
133
134impl Display for Uuid7 {
135	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
136		write!(f, "{}", self.0)
137	}
138}
139
140#[cfg(test)]
141#[allow(clippy::approx_constant)]
142pub mod tests {
143	use super::*;
144	use crate::clock::testing::{TestClock, TestRng};
145
146	fn test_clock_and_rng() -> (TestClock, TestClock, TestRng) {
147		let clock = TestClock::from_millis(1000);
148		(clock.clone(), clock, TestRng)
149	}
150
151	#[cfg(feature = "host")]
152	#[test]
153	fn test_uuid4_generate() {
154		let uuid4 = Uuid4::generate();
155		assert_eq!(uuid4.get_version_num(), 4);
156	}
157
158	#[cfg(feature = "host")]
159	#[test]
160	fn test_uuid4_equality() {
161		let std_uuid = StdUuid::new_v4();
162		let uuid4_a = Uuid4(std_uuid);
163		let uuid4_b = Uuid4(std_uuid);
164		let uuid4_c = Uuid4::generate();
165
166		assert_eq!(uuid4_a, uuid4_b);
167		assert_ne!(uuid4_a, uuid4_c);
168	}
169
170	#[cfg(feature = "host")]
171	#[test]
172	fn test_uuid4_ordering() {
173		let uuid4_a = Uuid4::generate();
174		let uuid4_b = Uuid4::generate();
175
176		let cmp1 = uuid4_a.cmp(&uuid4_b);
177		let cmp2 = uuid4_a.cmp(&uuid4_b);
178		assert_eq!(cmp1, cmp2);
179
180		assert_eq!(uuid4_a.cmp(&uuid4_a), Ordering::Equal);
181	}
182
183	#[cfg(feature = "host")]
184	#[test]
185	fn test_uuid4_display() {
186		let std_uuid = StdUuid::new_v4();
187		let uuid4 = Uuid4(std_uuid);
188
189		assert_eq!(format!("{}", uuid4), format!("{}", std_uuid));
190	}
191
192	#[test]
193	fn test_uuid7_generate() {
194		let (_, clock, rng) = test_clock_and_rng();
195		let uuid7 = Uuid7::generate(&clock, &rng);
196		assert_eq!(uuid7.get_version_num(), 7);
197	}
198
199	#[test]
200	fn test_uuid7_equality() {
201		let (mock, clock, rng) = test_clock_and_rng();
202		let uuid7_a = Uuid7::generate(&clock, &rng);
203		let uuid7_b = Uuid7(uuid7_a.0);
204		mock.advance_millis(1);
205		let uuid7_c = Uuid7::generate(&clock, &rng);
206
207		assert_eq!(uuid7_a, uuid7_b);
208		assert_ne!(uuid7_a, uuid7_c);
209	}
210
211	#[test]
212	fn test_uuid7_ordering() {
213		let (mock, clock, rng) = test_clock_and_rng();
214		let uuid7_a = Uuid7::generate(&clock, &rng);
215		mock.advance_millis(1);
216		let uuid7_b = Uuid7::generate(&clock, &rng);
217
218		let cmp1 = uuid7_a.cmp(&uuid7_b);
219		let cmp2 = uuid7_a.cmp(&uuid7_b);
220		assert_eq!(cmp1, cmp2);
221
222		assert_eq!(uuid7_a.cmp(&uuid7_a), Ordering::Equal);
223	}
224
225	#[test]
226	fn test_uuid7_display() {
227		let (_, clock, rng) = test_clock_and_rng();
228		let uuid7 = Uuid7::generate(&clock, &rng);
229		let display = format!("{}", uuid7);
230		assert!(!display.is_empty());
231	}
232
233	#[test]
234	fn test_uuid7_timestamp_ordering() {
235		let (mock, clock, rng) = test_clock_and_rng();
236		let uuid7_first = Uuid7::generate(&clock, &rng);
237		mock.advance_millis(1);
238		let uuid7_second = Uuid7::generate(&clock, &rng);
239
240		assert!(uuid7_first < uuid7_second);
241	}
242}