Skip to main content

reifydb_codec/encoded/
uuid7.rs

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