reifydb_codec/primitive/
decimal.rs1use bigdecimal::BigDecimal as StdBigDecimal;
5use num_bigint::BigInt as StdBigInt;
6use reifydb_value::{
7 reifydb_assertions,
8 value::{decimal::Decimal, value_type::ValueType},
9};
10
11use crate::row::{bytes::RowBuilder, shape::RowShape};
12
13#[cfg(reifydb_assertions)]
14const MODE_DYNAMIC: u128 = 0x80000000000000000000000000000000;
15#[cfg(reifydb_assertions)]
16const MODE_MASK: u128 = 0x80000000000000000000000000000000;
17
18const DYNAMIC_OFFSET_MASK: u128 = 0x0000000000000000FFFFFFFFFFFFFFFF;
19const DYNAMIC_LENGTH_MASK: u128 = 0x7FFFFFFFFFFFFFFF0000000000000000;
20
21impl RowShape {
22 pub fn set_decimal(&self, row: &mut impl RowBuilder, index: usize, value: &Decimal) {
23 reifydb_assertions! {
24 assert!(
25 row.len() >= self.total_static_size(),
26 "row/shape size mismatch: row.len()={} < total_static_size()={}",
27 row.len(),
28 self.total_static_size()
29 );
30 assert_eq!(*self.fields()[index].constraint.get_type().inner_type(), ValueType::Decimal);
31 }
32
33 let (mantissa, original_scale) = value.inner().as_bigint_and_exponent();
34 let scale_bytes = original_scale.to_le_bytes();
35 let digits_bytes = mantissa.to_signed_bytes_le();
36
37 let mut serialized = Vec::with_capacity(8 + digits_bytes.len());
38 serialized.extend_from_slice(&scale_bytes);
39 serialized.extend_from_slice(&digits_bytes);
40
41 self.replace_dynamic_data(row, index, &serialized);
42 }
43
44 pub fn get_decimal(&self, row: &[u8], index: usize) -> Decimal {
45 let field = &self.fields()[index];
46 reifydb_assertions! {
47 assert!(
48 row.len() >= self.total_static_size(),
49 "row/shape size mismatch: row.len()={} < total_static_size()={}",
50 row.len(),
51 self.total_static_size()
52 );
53 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Decimal);
54 }
55
56 let packed = unsafe { (row.as_ptr().add(field.offset as usize) as *const u128).read_unaligned() };
59 let packed = u128::from_le(packed);
60
61 reifydb_assertions! {
62 assert!(packed & MODE_MASK == MODE_DYNAMIC, "Expected dynamic storage");
63 }
64
65 let offset = (packed & DYNAMIC_OFFSET_MASK) as usize;
66 let length = ((packed & DYNAMIC_LENGTH_MASK) >> 64) as usize;
67
68 let dynamic_start = self.dynamic_section_start();
69 let data_bytes = &row[dynamic_start + offset..dynamic_start + offset + length];
70
71 let original_scale = i64::from_le_bytes(data_bytes[0..8].try_into().unwrap());
72 let mantissa = StdBigInt::from_signed_bytes_le(&data_bytes[8..]);
73
74 let big_decimal = StdBigDecimal::new(mantissa, original_scale);
75
76 Decimal::from(big_decimal)
77 }
78
79 pub fn try_get_decimal(&self, row: &[u8], index: usize) -> Option<Decimal> {
80 if self.is_defined(row, index)
81 && matches!(self.fields()[index].constraint.get_type().inner_type(), ValueType::Decimal)
82 {
83 Some(self.get_decimal(row, index))
84 } else {
85 None
86 }
87 }
88}