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