1use std::str;
5
6use reifydb_value::{
7 reifydb_assertions,
8 value::{
9 Value,
10 blob::Blob,
11 date::Date,
12 datetime::DateTime,
13 duration::Duration,
14 identity::IdentityId,
15 ordered_f32::OrderedF32,
16 ordered_f64::OrderedF64,
17 time::Time,
18 uuid::{Uuid4, Uuid7},
19 value_type::ValueType,
20 },
21};
22use uuid::Uuid;
23
24use crate::encoded::{row::EncodedRow, shape::RowShape};
25
26pub fn encode_value(value: &Value) -> Vec<u8> {
27 match value {
28 Value::Boolean(v) => vec![ValueType::Boolean.to_u8(), *v as u8],
29
30 Value::Uint1(v) => vec![ValueType::Uint1.to_u8(), *v],
31 Value::Uint2(v) => {
32 let mut b = vec![ValueType::Uint2.to_u8()];
33 b.extend_from_slice(&v.to_le_bytes());
34 b
35 }
36 Value::Uint4(v) => {
37 let mut b = vec![ValueType::Uint4.to_u8()];
38 b.extend_from_slice(&v.to_le_bytes());
39 b
40 }
41 Value::Uint8(v) => {
42 let mut b = vec![ValueType::Uint8.to_u8()];
43 b.extend_from_slice(&v.to_le_bytes());
44 b
45 }
46 Value::Uint16(v) => {
47 let mut b = vec![ValueType::Uint16.to_u8()];
48 b.extend_from_slice(&v.to_le_bytes());
49 b
50 }
51
52 Value::Int1(v) => vec![ValueType::Int1.to_u8(), *v as u8],
53 Value::Int2(v) => {
54 let mut b = vec![ValueType::Int2.to_u8()];
55 b.extend_from_slice(&v.to_le_bytes());
56 b
57 }
58 Value::Int4(v) => {
59 let mut b = vec![ValueType::Int4.to_u8()];
60 b.extend_from_slice(&v.to_le_bytes());
61 b
62 }
63 Value::Int8(v) => {
64 let mut b = vec![ValueType::Int8.to_u8()];
65 b.extend_from_slice(&v.to_le_bytes());
66 b
67 }
68 Value::Int16(v) => {
69 let mut b = vec![ValueType::Int16.to_u8()];
70 b.extend_from_slice(&v.to_le_bytes());
71 b
72 }
73
74 Value::Float4(v) => {
75 let mut b = vec![ValueType::Float4.to_u8()];
76 b.extend_from_slice(&v.value().to_bits().to_le_bytes());
77 b
78 }
79 Value::Float8(v) => {
80 let mut b = vec![ValueType::Float8.to_u8()];
81 b.extend_from_slice(&v.value().to_bits().to_le_bytes());
82 b
83 }
84
85 Value::Date(v) => {
86 let mut b = vec![ValueType::Date.to_u8()];
87 b.extend_from_slice(&v.to_days_since_epoch().to_le_bytes());
88 b
89 }
90 Value::DateTime(v) => {
91 let mut b = vec![ValueType::DateTime.to_u8()];
92 b.extend_from_slice(&v.to_nanos().to_le_bytes());
93 b
94 }
95 Value::Time(v) => {
96 let mut b = vec![ValueType::Time.to_u8()];
97 b.extend_from_slice(&v.to_nanos_since_midnight().to_le_bytes());
98 b
99 }
100 Value::Duration(v) => {
101 let mut b = vec![ValueType::Duration.to_u8()];
102 b.extend_from_slice(&v.get_months().to_le_bytes());
103 b.extend_from_slice(&v.get_days().to_le_bytes());
104 b.extend_from_slice(&v.get_nanos().to_le_bytes());
105 b
106 }
107
108 Value::Uuid4(v) => {
109 let mut b = vec![ValueType::Uuid4.to_u8()];
110 b.extend_from_slice(v.as_bytes());
111 b
112 }
113 Value::Uuid7(v) => {
114 let mut b = vec![ValueType::Uuid7.to_u8()];
115 b.extend_from_slice(v.as_bytes());
116 b
117 }
118 Value::IdentityId(v) => {
119 let mut b = vec![ValueType::IdentityId.to_u8()];
120 b.extend_from_slice(v.as_bytes());
121 b
122 }
123
124 Value::Utf8(v) => {
125 let s = v.as_bytes();
126 let mut b = vec![ValueType::Utf8.to_u8()];
127 b.extend_from_slice(&(s.len() as u32).to_le_bytes());
128 b.extend_from_slice(s);
129 b
130 }
131 Value::Blob(v) => {
132 let s = v.as_bytes();
133 let mut b = vec![ValueType::Blob.to_u8()];
134 b.extend_from_slice(&(s.len() as u32).to_le_bytes());
135 b.extend_from_slice(s);
136 b
137 }
138
139 Value::Int(_)
140 | Value::Uint(_)
141 | Value::Decimal(_)
142 | Value::DictionaryId(_)
143 | Value::Any(_)
144 | Value::None {
145 ..
146 }
147 | Value::Type(_)
148 | Value::List(_)
149 | Value::Record(_)
150 | Value::Tuple(_) => unreachable!("unsupported value type in Any encoding: {:?}", value),
151 }
152}
153
154pub fn decode_value(bytes: &[u8]) -> Value {
155 let type_byte = bytes[0];
156 let p = &bytes[1..];
157 let ty = ValueType::from_u8(type_byte);
158
159 match ty {
160 ValueType::Boolean => Value::Boolean(p[0] != 0),
161
162 ValueType::Uint1 => Value::Uint1(p[0]),
163 ValueType::Uint2 => Value::Uint2(u16::from_le_bytes([p[0], p[1]])),
164 ValueType::Uint4 => Value::Uint4(u32::from_le_bytes([p[0], p[1], p[2], p[3]])),
165 ValueType::Uint8 => Value::Uint8(u64::from_le_bytes(p[..8].try_into().unwrap())),
166 ValueType::Uint16 => Value::Uint16(u128::from_le_bytes(p[..16].try_into().unwrap())),
167
168 ValueType::Int1 => Value::Int1(p[0] as i8),
169 ValueType::Int2 => Value::Int2(i16::from_le_bytes([p[0], p[1]])),
170 ValueType::Int4 => Value::Int4(i32::from_le_bytes([p[0], p[1], p[2], p[3]])),
171 ValueType::Int8 => Value::Int8(i64::from_le_bytes(p[..8].try_into().unwrap())),
172 ValueType::Int16 => Value::Int16(i128::from_le_bytes(p[..16].try_into().unwrap())),
173
174 ValueType::Float4 => {
175 let bits = u32::from_le_bytes([p[0], p[1], p[2], p[3]]);
176 Value::Float4(OrderedF32::try_from(f32::from_bits(bits)).unwrap())
177 }
178 ValueType::Float8 => {
179 let bits = u64::from_le_bytes(p[..8].try_into().unwrap());
180 Value::Float8(OrderedF64::try_from(f64::from_bits(bits)).unwrap())
181 }
182
183 ValueType::Date => {
184 let days = i32::from_le_bytes([p[0], p[1], p[2], p[3]]);
185 Value::Date(Date::from_days_since_epoch(days).unwrap())
186 }
187 ValueType::DateTime => {
188 let nanos = u64::from_le_bytes(p[..8].try_into().unwrap());
189 Value::DateTime(DateTime::from_nanos(nanos))
190 }
191 ValueType::Time => {
192 let nanos = u64::from_le_bytes(p[..8].try_into().unwrap());
193 Value::Time(Time::from_nanos_since_midnight(nanos).unwrap())
194 }
195 ValueType::Duration => {
196 let months = i32::from_le_bytes([p[0], p[1], p[2], p[3]]);
197 let days = i32::from_le_bytes([p[4], p[5], p[6], p[7]]);
198 let nanos = i64::from_le_bytes(p[8..16].try_into().unwrap());
199 Value::Duration(Duration::new(months, days, nanos).unwrap())
200 }
201
202 ValueType::Uuid4 => {
203 let b: [u8; 16] = p[..16].try_into().unwrap();
204 Value::Uuid4(Uuid4::from(Uuid::from_bytes(b)))
205 }
206 ValueType::Uuid7 => {
207 let b: [u8; 16] = p[..16].try_into().unwrap();
208 Value::Uuid7(Uuid7::from(Uuid::from_bytes(b)))
209 }
210 ValueType::IdentityId => {
211 let b: [u8; 16] = p[..16].try_into().unwrap();
212 Value::IdentityId(IdentityId::from(Uuid7::from(Uuid::from_bytes(b))))
213 }
214
215 ValueType::Utf8 => {
216 let len = u32::from_le_bytes([p[0], p[1], p[2], p[3]]) as usize;
217 let s = str::from_utf8(&p[4..4 + len]).unwrap();
218 Value::Utf8(s.to_string())
219 }
220 ValueType::Blob => {
221 let len = u32::from_le_bytes([p[0], p[1], p[2], p[3]]) as usize;
222 Value::Blob(Blob::from_slice(&p[4..4 + len]))
223 }
224
225 _ => unreachable!("unsupported type byte {} in Any decoding", type_byte),
226 }
227}
228
229impl RowShape {
230 pub fn set_any(&self, row: &mut EncodedRow, index: usize, value: &Value) {
231 reifydb_assertions! {
232 assert!(
233 row.len() >= self.total_static_size(),
234 "row/shape size mismatch: row.len()={} < total_static_size()={}",
235 row.len(),
236 self.total_static_size()
237 );
238 assert_eq!(*self.fields()[index].constraint.get_type().inner_type(), ValueType::Any);
239 }
240 let encoded = encode_value(value);
241 self.replace_dynamic_data(row, index, &encoded);
242 }
243
244 pub fn get_any(&self, row: &EncodedRow, index: usize) -> Value {
245 let field = &self.fields()[index];
246 reifydb_assertions! {
247 assert!(
248 row.len() >= self.total_static_size(),
249 "row/shape size mismatch: row.len()={} < total_static_size()={}",
250 row.len(),
251 self.total_static_size()
252 );
253 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Any);
254 }
255
256 let ref_slice = &row.as_slice()[field.offset as usize..field.offset as usize + 8];
257 let offset = u32::from_le_bytes([ref_slice[0], ref_slice[1], ref_slice[2], ref_slice[3]]) as usize;
258 let length = u32::from_le_bytes([ref_slice[4], ref_slice[5], ref_slice[6], ref_slice[7]]) as usize;
259
260 let dynamic_start = self.dynamic_section_start();
261 let data_start = dynamic_start + offset;
262 let data_slice = &row.as_slice()[data_start..data_start + length];
263
264 decode_value(data_slice)
265 }
266}
267
268#[cfg(test)]
269pub mod tests {
270 use std::f64::consts::E;
271
272 use reifydb_runtime::context::{
273 clock::{Clock, MockClock},
274 rng::Rng,
275 };
276 use reifydb_value::value::{
277 Value,
278 blob::Blob,
279 date::Date,
280 datetime::DateTime,
281 ordered_f32::OrderedF32,
282 ordered_f64::OrderedF64,
283 time::Time,
284 uuid::{Uuid4, Uuid7},
285 value_type::ValueType,
286 };
287
288 use crate::encoded::shape::RowShape;
289
290 fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
291 let mock = MockClock::from_millis(1000);
292 let clock = Clock::Mock(mock.clone());
293 let rng = Rng::seeded(42);
294 (mock, clock, rng)
295 }
296
297 #[test]
298 fn test_any_boolean() {
299 let shape = RowShape::testing(&[ValueType::Any]);
300 let mut row = shape.allocate();
301 shape.set_any(&mut row, 0, &Value::Boolean(true));
302 assert_eq!(shape.get_any(&row, 0), Value::Boolean(true));
303 }
304
305 #[test]
306 fn test_any_integers() {
307 let shape = RowShape::testing(&[ValueType::Any]);
308
309 let cases: &[Value] = &[
310 Value::Int1(-42),
311 Value::Int2(-1000),
312 Value::Int4(-100000),
313 Value::Int8(i64::MIN),
314 Value::Int16(i128::MAX),
315 Value::Uint1(255),
316 Value::Uint2(65535),
317 Value::Uint4(u32::MAX),
318 Value::Uint8(u64::MAX),
319 Value::Uint16(u128::MAX),
320 ];
321
322 for case in cases {
323 let mut row = shape.allocate();
324 shape.set_any(&mut row, 0, case);
325 assert_eq!(&shape.get_any(&row, 0), case);
326 }
327 }
328
329 #[test]
330 fn test_any_floats() {
331 let shape = RowShape::testing(&[ValueType::Any]);
332
333 let f4 = Value::Float4(OrderedF32::try_from(3.14f32).unwrap());
334 let mut row = shape.allocate();
335 shape.set_any(&mut row, 0, &f4);
336 assert_eq!(shape.get_any(&row, 0), f4);
337
338 let f8 = Value::Float8(OrderedF64::try_from(E).unwrap());
339 let mut row2 = shape.allocate();
340 shape.set_any(&mut row2, 0, &f8);
341 assert_eq!(shape.get_any(&row2, 0), f8);
342 }
343
344 #[test]
345 fn test_any_temporal() {
346 let shape = RowShape::testing(&[ValueType::Any]);
347
348 let date = Value::Date(Date::new(2025, 7, 4).unwrap());
349 let mut row = shape.allocate();
350 shape.set_any(&mut row, 0, &date);
351 assert_eq!(shape.get_any(&row, 0), date);
352
353 let dt = Value::DateTime(DateTime::new(2025, 1, 1, 12, 0, 0, 0).unwrap());
354 let mut row2 = shape.allocate();
355 shape.set_any(&mut row2, 0, &dt);
356 assert_eq!(shape.get_any(&row2, 0), dt);
357
358 let t = Value::Time(Time::new(14, 30, 45, 123456789).unwrap());
359 let mut row3 = shape.allocate();
360 shape.set_any(&mut row3, 0, &t);
361 assert_eq!(shape.get_any(&row3, 0), t);
362
363 let dur = Value::duration_seconds(3600);
364 let mut row4 = shape.allocate();
365 shape.set_any(&mut row4, 0, &dur);
366 assert_eq!(shape.get_any(&row4, 0), dur);
367 }
368
369 #[test]
370 fn test_any_uuid() {
371 let (_, clock, rng) = test_clock_and_rng();
372 let shape = RowShape::testing(&[ValueType::Any]);
373
374 let u4 = Value::Uuid4(Uuid4::generate());
375 let mut row = shape.allocate();
376 shape.set_any(&mut row, 0, &u4);
377 assert_eq!(shape.get_any(&row, 0), u4);
378
379 let u7 = Value::Uuid7(Uuid7::generate(&clock, &rng));
380 let mut row2 = shape.allocate();
381 shape.set_any(&mut row2, 0, &u7);
382 assert_eq!(shape.get_any(&row2, 0), u7);
383 }
384
385 #[test]
386 fn test_any_utf8() {
387 let shape = RowShape::testing(&[ValueType::Any]);
388 let v = Value::Utf8("hello, world!".to_string());
389 let mut row = shape.allocate();
390 shape.set_any(&mut row, 0, &v);
391 assert_eq!(shape.get_any(&row, 0), v);
392 }
393
394 #[test]
395 fn test_any_blob() {
396 let shape = RowShape::testing(&[ValueType::Any]);
397 let v = Value::Blob(Blob::from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]));
398 let mut row = shape.allocate();
399 shape.set_any(&mut row, 0, &v);
400 assert_eq!(shape.get_any(&row, 0), v);
401 }
402
403 #[test]
404 fn test_any_none_via_set_value() {
405 let shape = RowShape::testing(&[ValueType::Any]);
406 let mut row = shape.allocate();
407 shape.set_value(&mut row, 0, &Value::none());
408 assert!(!row.is_defined(0));
409 assert_eq!(shape.get_value(&row, 0), Value::none());
410 }
411
412 #[test]
413 fn test_any_roundtrip_via_set_get_value() {
414 let shape = RowShape::testing(&[ValueType::Any]);
415
416 let cases: &[Value] = &[
417 Value::Boolean(false),
418 Value::Int4(42),
419 Value::Utf8("test".to_string()),
420 Value::Uint8(1234567890),
421 ];
422
423 for inner in cases {
424 let wrapped = Value::any(inner.clone());
425 let mut row = shape.allocate();
426 shape.set_value(&mut row, 0, &wrapped);
427 let retrieved = shape.get_value(&row, 0);
428 assert_eq!(retrieved, wrapped, "roundtrip failed for {:?}", inner);
429 }
430 }
431
432 #[test]
433 fn test_any_multiple_fields() {
434 let shape = RowShape::testing(&[ValueType::Any, ValueType::Int4, ValueType::Any]);
435 let mut row = shape.allocate();
436
437 shape.set_any(&mut row, 0, &Value::Utf8("first".to_string()));
438 shape.set_i32(&mut row, 1, 99);
439 shape.set_any(&mut row, 2, &Value::Boolean(true));
440
441 assert_eq!(shape.get_any(&row, 0), Value::Utf8("first".to_string()));
442 assert_eq!(shape.get_i32(&row, 1), 99);
443 assert_eq!(shape.get_any(&row, 2), Value::Boolean(true));
444 }
445
446 #[test]
447 fn test_update_any() {
448 let shape = RowShape::testing(&[ValueType::Any]);
449 let mut row = shape.allocate();
450
451 shape.set_any(&mut row, 0, &Value::Int4(42));
452 assert_eq!(shape.get_any(&row, 0), Value::Int4(42));
453
454 shape.set_any(&mut row, 0, &Value::Utf8("hello".to_string()));
456 assert_eq!(shape.get_any(&row, 0), Value::Utf8("hello".to_string()));
457
458 shape.set_any(&mut row, 0, &Value::Boolean(true));
460 assert_eq!(shape.get_any(&row, 0), Value::Boolean(true));
461 }
462
463 #[test]
464 fn test_update_any_with_other_dynamic_fields() {
465 let shape = RowShape::testing(&[ValueType::Any, ValueType::Utf8, ValueType::Any]);
466 let mut row = shape.allocate();
467
468 shape.set_any(&mut row, 0, &Value::Int4(1));
469 shape.set_utf8(&mut row, 1, "middle");
470 shape.set_any(&mut row, 2, &Value::Boolean(false));
471
472 shape.set_any(&mut row, 0, &Value::Utf8("a long string value".to_string()));
474
475 assert_eq!(shape.get_any(&row, 0), Value::Utf8("a long string value".to_string()));
476 assert_eq!(shape.get_utf8(&row, 1), "middle");
477 assert_eq!(shape.get_any(&row, 2), Value::Boolean(false));
478 }
479}