Skip to main content

reifydb_core/encoded/
uuid7.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::ptr;
5
6use reifydb_type::value::{r#type::Type, uuid::Uuid7};
7use uuid::Uuid;
8
9use crate::encoded::{row::EncodedRow, shape::RowShape};
10
11impl RowShape {
12	pub fn set_uuid7(&self, row: &mut EncodedRow, index: usize, value: Uuid7) {
13		let field = &self.fields()[index];
14		debug_assert!(row.len() >= self.total_static_size());
15		debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uuid7);
16		row.set_valid(index, true);
17		unsafe {
18			// UUIDs are 16 bytes
19			ptr::write_unaligned(
20				row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut [u8; 16],
21				*value.as_bytes(),
22			);
23		}
24	}
25
26	pub fn get_uuid7(&self, row: &EncodedRow, index: usize) -> Uuid7 {
27		let field = &self.fields()[index];
28		debug_assert!(row.len() >= self.total_static_size());
29		debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uuid7);
30		unsafe {
31			// UUIDs are 16 bytes
32			let bytes: [u8; 16] =
33				ptr::read_unaligned(row.as_ptr().add(field.offset as usize) as *const [u8; 16]);
34			Uuid7::from(Uuid::from_bytes(bytes))
35		}
36	}
37
38	pub fn try_get_uuid7(&self, row: &EncodedRow, index: usize) -> Option<Uuid7> {
39		if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Uuid7 {
40			Some(self.get_uuid7(row, index))
41		} else {
42			None
43		}
44	}
45}
46
47#[cfg(test)]
48pub mod tests {
49	use reifydb_runtime::context::{
50		clock::{Clock, MockClock},
51		rng::Rng,
52	};
53	use reifydb_type::value::{r#type::Type, uuid::Uuid7};
54
55	use crate::encoded::shape::RowShape;
56
57	fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
58		let mock = MockClock::from_millis(1000);
59		let clock = Clock::Mock(mock.clone());
60		let rng = Rng::seeded(42);
61		(mock, clock, rng)
62	}
63
64	#[test]
65	fn test_set_get_uuid7() {
66		let (_mock, clock, rng) = test_clock_and_rng();
67		let shape = RowShape::testing(&[Type::Uuid7]);
68		let mut row = shape.allocate();
69
70		let uuid = Uuid7::generate(&clock, &rng);
71		shape.set_uuid7(&mut row, 0, uuid.clone());
72		assert_eq!(shape.get_uuid7(&row, 0), uuid);
73	}
74
75	#[test]
76	fn test_try_get_uuid7() {
77		let (_mock, clock, rng) = test_clock_and_rng();
78		let shape = RowShape::testing(&[Type::Uuid7]);
79		let mut row = shape.allocate();
80
81		assert_eq!(shape.try_get_uuid7(&row, 0), None);
82
83		let uuid = Uuid7::generate(&clock, &rng);
84		shape.set_uuid7(&mut row, 0, uuid.clone());
85		assert_eq!(shape.try_get_uuid7(&row, 0), Some(uuid));
86	}
87
88	#[test]
89	fn test_multiple_generations() {
90		let (mock, clock, rng) = test_clock_and_rng();
91		let shape = RowShape::testing(&[Type::Uuid7]);
92
93		// Generate multiple UUIDs and ensure they're different
94		let mut uuids = Vec::new();
95		for _ in 0..10 {
96			let mut row = shape.allocate();
97			let uuid = Uuid7::generate(&clock, &rng);
98			shape.set_uuid7(&mut row, 0, uuid.clone());
99			let retrieved = shape.get_uuid7(&row, 0);
100			assert_eq!(retrieved, uuid);
101			uuids.push(uuid);
102			mock.advance_millis(1);
103		}
104
105		// Ensure all generated UUIDs are unique
106		for i in 0..uuids.len() {
107			for j in (i + 1)..uuids.len() {
108				assert_ne!(uuids[i], uuids[j], "UUIDs should be unique");
109			}
110		}
111	}
112
113	#[test]
114	fn test_version_check() {
115		let (_mock, clock, rng) = test_clock_and_rng();
116		let shape = RowShape::testing(&[Type::Uuid7]);
117		let mut row = shape.allocate();
118
119		let uuid = Uuid7::generate(&clock, &rng);
120		shape.set_uuid7(&mut row, 0, uuid.clone());
121		let retrieved = shape.get_uuid7(&row, 0);
122
123		// Verify it's a version 7 UUID
124		assert_eq!(retrieved.get_version_num(), 7);
125	}
126
127	#[test]
128	fn test_timestamp_ordering() {
129		let (mock, clock, rng) = test_clock_and_rng();
130		let shape = RowShape::testing(&[Type::Uuid7]);
131
132		// Generate UUIDs in sequence - they should be ordered by
133		// timestamp
134		let mut uuids = Vec::new();
135		for _ in 0..5 {
136			let mut row = shape.allocate();
137			let uuid = Uuid7::generate(&clock, &rng);
138			shape.set_uuid7(&mut row, 0, uuid.clone());
139			let retrieved = shape.get_uuid7(&row, 0);
140			assert_eq!(retrieved, uuid);
141			uuids.push(uuid);
142
143			// Advance clock to ensure different timestamps
144			mock.advance_millis(1);
145		}
146
147		// Verify that UUIDs are ordered (timestamp-based)
148		for i in 1..uuids.len() {
149			assert!(uuids[i].as_bytes() >= uuids[i - 1].as_bytes(), "UUID7s should be timestamp-ordered");
150		}
151	}
152
153	#[test]
154	fn test_mixed_with_other_types() {
155		let (mock, clock, rng) = test_clock_and_rng();
156		let shape = RowShape::testing(&[Type::Uuid7, Type::Boolean, Type::Uuid7, Type::Int4]);
157		let mut row = shape.allocate();
158
159		let uuid1 = Uuid7::generate(&clock, &rng);
160		mock.advance_millis(1);
161		let uuid2 = Uuid7::generate(&clock, &rng);
162
163		shape.set_uuid7(&mut row, 0, uuid1.clone());
164		shape.set_bool(&mut row, 1, true);
165		shape.set_uuid7(&mut row, 2, uuid2.clone());
166		shape.set_i32(&mut row, 3, 42);
167
168		assert_eq!(shape.get_uuid7(&row, 0), uuid1);
169		assert_eq!(shape.get_bool(&row, 1), true);
170		assert_eq!(shape.get_uuid7(&row, 2), uuid2);
171		assert_eq!(shape.get_i32(&row, 3), 42);
172	}
173
174	#[test]
175	fn test_undefined_handling() {
176		let (_mock, clock, rng) = test_clock_and_rng();
177		let shape = RowShape::testing(&[Type::Uuid7, Type::Uuid7]);
178		let mut row = shape.allocate();
179
180		let uuid = Uuid7::generate(&clock, &rng);
181		shape.set_uuid7(&mut row, 0, uuid.clone());
182
183		assert_eq!(shape.try_get_uuid7(&row, 0), Some(uuid));
184		assert_eq!(shape.try_get_uuid7(&row, 1), None);
185
186		shape.set_none(&mut row, 0);
187		assert_eq!(shape.try_get_uuid7(&row, 0), None);
188	}
189
190	#[test]
191	fn test_persistence() {
192		let (_mock, clock, rng) = test_clock_and_rng();
193		let shape = RowShape::testing(&[Type::Uuid7]);
194		let mut row = shape.allocate();
195
196		let uuid = Uuid7::generate(&clock, &rng);
197		let uuid_string = uuid.to_string();
198
199		shape.set_uuid7(&mut row, 0, uuid.clone());
200		let retrieved = shape.get_uuid7(&row, 0);
201
202		assert_eq!(retrieved, uuid);
203		assert_eq!(retrieved.to_string(), uuid_string);
204		assert_eq!(retrieved.as_bytes(), uuid.as_bytes());
205	}
206
207	#[test]
208	fn test_clone_consistency() {
209		let (_mock, clock, rng) = test_clock_and_rng();
210		let shape = RowShape::testing(&[Type::Uuid7]);
211		let mut row = shape.allocate();
212
213		let original_uuid = Uuid7::generate(&clock, &rng);
214		shape.set_uuid7(&mut row, 0, original_uuid.clone());
215
216		let retrieved_uuid = shape.get_uuid7(&row, 0);
217		assert_eq!(retrieved_uuid, original_uuid);
218
219		// Verify that the byte representation is identical
220		assert_eq!(retrieved_uuid.as_bytes(), original_uuid.as_bytes());
221	}
222
223	#[test]
224	fn test_multiple_fields() {
225		let (mock, clock, rng) = test_clock_and_rng();
226		let shape = RowShape::testing(&[Type::Uuid7, Type::Uuid7, Type::Uuid7]);
227		let mut row = shape.allocate();
228
229		let uuid1 = Uuid7::generate(&clock, &rng);
230		mock.advance_millis(1);
231		let uuid2 = Uuid7::generate(&clock, &rng);
232		mock.advance_millis(1);
233		let uuid3 = Uuid7::generate(&clock, &rng);
234
235		shape.set_uuid7(&mut row, 0, uuid1.clone());
236		shape.set_uuid7(&mut row, 1, uuid2.clone());
237		shape.set_uuid7(&mut row, 2, uuid3.clone());
238
239		assert_eq!(shape.get_uuid7(&row, 0), uuid1);
240		assert_eq!(shape.get_uuid7(&row, 1), uuid2);
241		assert_eq!(shape.get_uuid7(&row, 2), uuid3);
242
243		// Ensure all UUIDs are different
244		assert_ne!(uuid1, uuid2);
245		assert_ne!(uuid1, uuid3);
246		assert_ne!(uuid2, uuid3);
247	}
248
249	#[test]
250	fn test_format_consistency() {
251		let (_mock, clock, rng) = test_clock_and_rng();
252		let shape = RowShape::testing(&[Type::Uuid7]);
253		let mut row = shape.allocate();
254
255		let uuid = Uuid7::generate(&clock, &rng);
256		let original_string = uuid.to_string();
257
258		shape.set_uuid7(&mut row, 0, uuid.clone());
259		let retrieved = shape.get_uuid7(&row, 0);
260		let retrieved_string = retrieved.to_string();
261
262		assert_eq!(original_string, retrieved_string);
263
264		// Verify UUID string format (8-4-4-4-12)
265		assert_eq!(original_string.len(), 36);
266		assert_eq!(original_string.matches('-').count(), 4);
267	}
268
269	#[test]
270	fn test_byte_level_storage() {
271		let (_mock, clock, rng) = test_clock_and_rng();
272		let shape = RowShape::testing(&[Type::Uuid7]);
273		let mut row = shape.allocate();
274
275		let uuid = Uuid7::generate(&clock, &rng);
276		let original_bytes = *uuid.as_bytes();
277
278		shape.set_uuid7(&mut row, 0, uuid.clone());
279		let retrieved = shape.get_uuid7(&row, 0);
280		let retrieved_bytes = *retrieved.as_bytes();
281
282		assert_eq!(original_bytes, retrieved_bytes);
283
284		// Verify that it's exactly 16 bytes
285		assert_eq!(original_bytes.len(), 16);
286		assert_eq!(retrieved_bytes.len(), 16);
287	}
288
289	#[test]
290	fn test_time_based_properties() {
291		let (mock, clock, rng) = test_clock_and_rng();
292		let shape = RowShape::testing(&[Type::Uuid7]);
293
294		// Generate UUIDs at different times
295		let uuid1 = Uuid7::generate(&clock, &rng);
296		mock.advance_millis(2);
297		let uuid2 = Uuid7::generate(&clock, &rng);
298
299		let mut row1 = shape.allocate();
300		let mut row2 = shape.allocate();
301
302		shape.set_uuid7(&mut row1, 0, uuid1.clone());
303		shape.set_uuid7(&mut row2, 0, uuid2.clone());
304
305		let retrieved1 = shape.get_uuid7(&row1, 0);
306		let retrieved2 = shape.get_uuid7(&row2, 0);
307
308		// The second UUID should be "greater" due to timestamp ordering
309		assert!(retrieved2.as_bytes() > retrieved1.as_bytes());
310	}
311
312	#[test]
313	fn test_try_get_uuid7_wrong_type() {
314		let shape = RowShape::testing(&[Type::Boolean]);
315		let mut row = shape.allocate();
316
317		shape.set_bool(&mut row, 0, true);
318
319		assert_eq!(shape.try_get_uuid7(&row, 0), None);
320	}
321}