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