1use 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 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 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 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 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 mock.advance_millis(1);
160 }
161
162 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 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 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 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 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 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 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}