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