1use std::ptr;
5
6use num_bigint::{BigInt, BigUint};
7use num_traits::ToPrimitive;
8use reifydb_value::{
9 reifydb_assertions,
10 value::{uint::Uint, value_type::ValueType},
11};
12
13use crate::encoded::{row::EncodedRow, shape::RowShape};
14
15const MODE_INLINE: u128 = 0x00000000000000000000000000000000;
16const MODE_MASK: u128 = 0x80000000000000000000000000000000;
17
18const INLINE_VALUE_MASK: u128 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
19
20const DYNAMIC_OFFSET_MASK: u128 = 0x0000000000000000FFFFFFFFFFFFFFFF;
21const DYNAMIC_LENGTH_MASK: u128 = 0x7FFFFFFFFFFFFFFF0000000000000000;
22
23impl RowShape {
24 pub fn set_uint(&self, row: &mut EncodedRow, index: usize, value: &Uint) {
25 let field = &self.fields()[index];
26 reifydb_assertions! {
27 assert!(
28 row.len() >= self.total_static_size(),
29 "row/shape size mismatch: row.len()={} < total_static_size()={}",
30 row.len(),
31 self.total_static_size()
32 );
33 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Uint);
34 }
35
36 let unsigned_value = value.0.to_biguint().unwrap_or(BigUint::from(0u32));
37
38 if let Some(u128_val) = unsigned_value.to_u128()
39 && u128_val < (1u128 << 127)
40 {
41 self.remove_dynamic_data(row, index);
42
43 let packed = MODE_INLINE | (u128_val & INLINE_VALUE_MASK);
44 unsafe {
45 ptr::write_unaligned(
46 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut u128,
47 packed.to_le(),
48 );
49 }
50 row.set_valid(index, true);
51 return;
52 }
53
54 let bytes = unsigned_value.to_bytes_le();
55 self.replace_dynamic_data(row, index, &bytes);
56 }
57
58 pub fn get_uint(&self, row: &EncodedRow, index: usize) -> Uint {
59 let field = &self.fields()[index];
60 reifydb_assertions! {
61 assert!(
62 row.len() >= self.total_static_size(),
63 "row/shape size mismatch: row.len()={} < total_static_size()={}",
64 row.len(),
65 self.total_static_size()
66 );
67 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Uint);
68 }
69
70 let packed = unsafe { (row.as_ptr().add(field.offset as usize) as *const u128).read_unaligned() };
71 let packed = u128::from_le(packed);
72
73 let mode = packed & MODE_MASK;
74
75 if mode == MODE_INLINE {
76 let value = packed & INLINE_VALUE_MASK;
77
78 let unsigned = BigUint::from(value);
79 Uint::from(BigInt::from(unsigned))
80 } else {
81 let offset = (packed & DYNAMIC_OFFSET_MASK) as usize;
82 let length = ((packed & DYNAMIC_LENGTH_MASK) >> 64) as usize;
83
84 let dynamic_start = self.dynamic_section_start();
85 let data_bytes = &row.as_slice()[dynamic_start + offset..dynamic_start + offset + length];
86
87 let unsigned = BigUint::from_bytes_le(data_bytes);
88 Uint::from(BigInt::from(unsigned))
89 }
90 }
91
92 pub fn try_get_uint(&self, row: &EncodedRow, index: usize) -> Option<Uint> {
93 if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::Uint {
94 Some(self.get_uint(row, index))
95 } else {
96 None
97 }
98 }
99}
100
101#[cfg(test)]
102pub mod tests {
103 use num_bigint::BigInt;
104 use num_traits::Zero;
105 use reifydb_value::value::{uint::Uint, value_type::ValueType};
106
107 use crate::encoded::shape::RowShape;
108
109 #[test]
110 fn test_u64_inline() {
111 let shape = RowShape::testing(&[ValueType::Uint]);
112 let mut row = shape.allocate();
113
114 let small = Uint::from(42u64);
116 shape.set_uint(&mut row, 0, &small);
117 assert!(row.is_defined(0));
118
119 let retrieved = shape.get_uint(&row, 0);
120 assert_eq!(retrieved, small);
121
122 let mut row2 = shape.allocate();
124 let large = Uint::from(999999999999u64);
125 shape.set_uint(&mut row2, 0, &large);
126 assert_eq!(shape.get_uint(&row2, 0), large);
127 }
128
129 #[test]
130 fn test_u128_boundary() {
131 let shape = RowShape::testing(&[ValueType::Uint]);
132 let mut row = shape.allocate();
133
134 let large = Uint::from(u64::MAX);
136 shape.set_uint(&mut row, 0, &large);
137 assert!(row.is_defined(0));
138
139 let retrieved = shape.get_uint(&row, 0);
140 assert_eq!(retrieved, large);
141
142 let mut row2 = shape.allocate();
144 let max_u127 = Uint::from(u128::MAX >> 1); shape.set_uint(&mut row2, 0, &max_u127);
146 assert_eq!(shape.get_uint(&row2, 0), max_u127);
147 }
148
149 #[test]
150 fn test_dynamic_storage() {
151 let shape = RowShape::testing(&[ValueType::Uint]);
152 let mut row = shape.allocate();
153
154 let huge = Uint::from(
157 BigInt::parse_bytes(b"123456789012345678901234567890123456789012345678901234567890", 10)
158 .unwrap(),
159 );
160
161 shape.set_uint(&mut row, 0, &huge);
162 assert!(row.is_defined(0));
163
164 let retrieved = shape.get_uint(&row, 0);
165 assert_eq!(retrieved, huge);
166 }
167
168 #[test]
169 fn test_zero() {
170 let shape = RowShape::testing(&[ValueType::Uint]);
171 let mut row = shape.allocate();
172
173 let zero = Uint::from(0);
174 shape.set_uint(&mut row, 0, &zero);
175 assert!(row.is_defined(0));
176
177 let retrieved = shape.get_uint(&row, 0);
178 assert!(retrieved.is_zero());
179 }
180
181 #[test]
182 fn test_try_get() {
183 let shape = RowShape::testing(&[ValueType::Uint]);
184 let mut row = shape.allocate();
185
186 assert_eq!(shape.try_get_uint(&row, 0), None);
188
189 let value = Uint::from(12345u64);
191 shape.set_uint(&mut row, 0, &value);
192 assert_eq!(shape.try_get_uint(&row, 0), Some(value));
193 }
194
195 #[test]
196 fn test_clone_on_write() {
197 let shape = RowShape::testing(&[ValueType::Uint]);
198 let row1 = shape.allocate();
199 let mut row2 = row1.clone();
200
201 let value = Uint::from(999999999999999u64);
202 shape.set_uint(&mut row2, 0, &value);
203
204 assert!(!row1.is_defined(0));
205 assert!(row2.is_defined(0));
206 assert_ne!(row1.as_ptr(), row2.as_ptr());
207 assert_eq!(shape.get_uint(&row2, 0), value);
208 }
209
210 #[test]
211 fn test_multiple_fields() {
212 let shape = RowShape::testing(&[
213 ValueType::Boolean,
214 ValueType::Uint,
215 ValueType::Utf8,
216 ValueType::Uint,
217 ValueType::Int4,
218 ]);
219 let mut row = shape.allocate();
220
221 shape.set_bool(&mut row, 0, true);
222
223 let small = Uint::from(100u64);
224 shape.set_uint(&mut row, 1, &small);
225
226 shape.set_utf8(&mut row, 2, "test");
227
228 let large = Uint::from(u128::MAX >> 1);
229 shape.set_uint(&mut row, 3, &large);
230
231 shape.set_i32(&mut row, 4, 42);
232
233 assert_eq!(shape.get_bool(&row, 0), true);
234 assert_eq!(shape.get_uint(&row, 1), small);
235 assert_eq!(shape.get_utf8(&row, 2), "test");
236 assert_eq!(shape.get_uint(&row, 3), large);
237 assert_eq!(shape.get_i32(&row, 4), 42);
238 }
239
240 #[test]
241 fn test_negative_input_handling() {
242 let shape = RowShape::testing(&[ValueType::Uint]);
243
244 let mut row1 = shape.allocate();
247 let negative = Uint::from(-42); shape.set_uint(&mut row1, 0, &negative);
249
250 let retrieved = shape.get_uint(&row1, 0);
252 assert_eq!(retrieved, Uint::from(0));
253 }
254
255 #[test]
256 fn test_try_get_uint_wrong_type() {
257 let shape = RowShape::testing(&[ValueType::Boolean]);
258 let mut row = shape.allocate();
259
260 shape.set_bool(&mut row, 0, true);
261
262 assert_eq!(shape.try_get_uint(&row, 0), None);
263 }
264
265 #[test]
266 fn test_update_uint_inline_to_inline() {
267 let shape = RowShape::testing(&[ValueType::Uint]);
268 let mut row = shape.allocate();
269
270 shape.set_uint(&mut row, 0, &Uint::from(42u64));
271 assert_eq!(shape.get_uint(&row, 0), Uint::from(42u64));
272
273 shape.set_uint(&mut row, 0, &Uint::from(999u64));
274 assert_eq!(shape.get_uint(&row, 0), Uint::from(999u64));
275 }
276
277 #[test]
278 fn test_update_uint_inline_to_dynamic() {
279 let shape = RowShape::testing(&[ValueType::Uint]);
280 let mut row = shape.allocate();
281
282 shape.set_uint(&mut row, 0, &Uint::from(42u64));
283
284 let huge = Uint::from(
285 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
286 );
287 shape.set_uint(&mut row, 0, &huge);
288 assert_eq!(shape.get_uint(&row, 0), huge);
289 }
290
291 #[test]
292 fn test_update_uint_dynamic_to_inline() {
293 let shape = RowShape::testing(&[ValueType::Uint]);
294 let mut row = shape.allocate();
295
296 let huge = Uint::from(
297 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
298 );
299 shape.set_uint(&mut row, 0, &huge);
300
301 shape.set_uint(&mut row, 0, &Uint::from(42u64));
302 assert_eq!(shape.get_uint(&row, 0), Uint::from(42u64));
303 assert_eq!(row.len(), shape.total_static_size());
304 }
305
306 #[test]
307 fn test_update_uint_with_other_dynamic_fields() {
308 let shape = RowShape::testing(&[ValueType::Uint, ValueType::Utf8]);
309 let mut row = shape.allocate();
310
311 let huge = Uint::from(
312 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
313 );
314 shape.set_uint(&mut row, 0, &huge);
315 shape.set_utf8(&mut row, 1, "hello");
316
317 shape.set_uint(&mut row, 0, &Uint::from(1u64));
319 assert_eq!(shape.get_uint(&row, 0), Uint::from(1u64));
320 assert_eq!(shape.get_utf8(&row, 1), "hello");
321 }
322}