reifydb_core/value/encoded/
uuid7.rs

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