1use 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 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 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 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 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 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 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 mock.advance_millis(1);
145 }
146
147 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 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 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 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 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 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 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}