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::{encoded::EncodedValues, schema::Schema};
11
12const MODE_INLINE: u128 = 0x00000000000000000000000000000000;
16const MODE_DYNAMIC: u128 = 0x80000000000000000000000000000000;
17const MODE_MASK: u128 = 0x80000000000000000000000000000000;
18
19const INLINE_VALUE_MASK: u128 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
21
22const DYNAMIC_OFFSET_MASK: u128 = 0x0000000000000000FFFFFFFFFFFFFFFF; const DYNAMIC_LENGTH_MASK: u128 = 0x7FFFFFFFFFFFFFFF0000000000000000; impl Schema {
27 pub fn set_uint(&self, row: &mut EncodedValues, index: usize, value: &Uint) {
31 let field = &self.fields()[index];
32 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uint);
33
34 let unsigned_value = value.0.to_biguint().unwrap_or(BigUint::from(0u32));
36
37 if let Some(u128_val) = unsigned_value.to_u128() {
39 if u128_val < (1u128 << 127) {
41 let packed = MODE_INLINE | (u128_val & INLINE_VALUE_MASK);
43 unsafe {
44 ptr::write_unaligned(
45 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut u128,
46 packed.to_le(),
47 );
48 }
49 row.set_valid(index, true);
50 return;
51 }
52 }
53
54 debug_assert!(!row.is_defined(index), "Uint field {} already set", index);
56
57 let bytes = unsigned_value.to_bytes_le();
59
60 let dynamic_offset = self.dynamic_section_size(row);
61 let total_size = bytes.len();
62
63 row.0.extend_from_slice(&bytes);
65
66 let offset_part = (dynamic_offset as u128) & DYNAMIC_OFFSET_MASK;
68 let length_part = ((total_size as u128) << 64) & DYNAMIC_LENGTH_MASK;
69 let packed = MODE_DYNAMIC | offset_part | length_part;
70
71 unsafe {
72 ptr::write_unaligned(
73 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut u128,
74 packed.to_le(),
75 );
76 }
77 row.set_valid(index, true);
78 }
79
80 pub fn get_uint(&self, row: &EncodedValues, index: usize) -> Uint {
82 let field = &self.fields()[index];
83 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uint);
84
85 let packed = unsafe { (row.as_ptr().add(field.offset as usize) as *const u128).read_unaligned() };
86 let packed = u128::from_le(packed);
87
88 let mode = packed & MODE_MASK;
89
90 if mode == MODE_INLINE {
91 let value = packed & INLINE_VALUE_MASK;
93 let unsigned = BigUint::from(value);
95 Uint::from(BigInt::from(unsigned))
96 } else {
97 let offset = (packed & DYNAMIC_OFFSET_MASK) as usize;
100 let length = ((packed & DYNAMIC_LENGTH_MASK) >> 64) as usize;
101
102 let dynamic_start = self.dynamic_section_start();
103 let data_bytes = &row.as_slice()[dynamic_start + offset..dynamic_start + offset + length];
104
105 let unsigned = BigUint::from_bytes_le(data_bytes);
107 Uint::from(BigInt::from(unsigned))
108 }
109 }
110
111 pub fn try_get_uint(&self, row: &EncodedValues, index: usize) -> Option<Uint> {
113 if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Uint {
114 Some(self.get_uint(row, index))
115 } else {
116 None
117 }
118 }
119}
120
121#[cfg(test)]
122pub mod tests {
123 use num_bigint::BigInt;
124 use num_traits::Zero;
125 use reifydb_type::value::{r#type::Type, uint::Uint};
126
127 use crate::encoded::schema::Schema;
128
129 #[test]
130 fn test_u64_inline() {
131 let schema = Schema::testing(&[Type::Uint]);
132 let mut row = schema.allocate();
133
134 let small = Uint::from(42u64);
136 schema.set_uint(&mut row, 0, &small);
137 assert!(row.is_defined(0));
138
139 let retrieved = schema.get_uint(&row, 0);
140 assert_eq!(retrieved, small);
141
142 let mut row2 = schema.allocate();
144 let large = Uint::from(999999999999u64);
145 schema.set_uint(&mut row2, 0, &large);
146 assert_eq!(schema.get_uint(&row2, 0), large);
147 }
148
149 #[test]
150 fn test_u128_boundary() {
151 let schema = Schema::testing(&[Type::Uint]);
152 let mut row = schema.allocate();
153
154 let large = Uint::from(u64::MAX);
156 schema.set_uint(&mut row, 0, &large);
157 assert!(row.is_defined(0));
158
159 let retrieved = schema.get_uint(&row, 0);
160 assert_eq!(retrieved, large);
161
162 let mut row2 = schema.allocate();
164 let max_u127 = Uint::from(u128::MAX >> 1); schema.set_uint(&mut row2, 0, &max_u127);
166 assert_eq!(schema.get_uint(&row2, 0), max_u127);
167 }
168
169 #[test]
170 fn test_dynamic_storage() {
171 let schema = Schema::testing(&[Type::Uint]);
172 let mut row = schema.allocate();
173
174 let huge = Uint::from(
177 BigInt::parse_bytes(b"123456789012345678901234567890123456789012345678901234567890", 10)
178 .unwrap(),
179 );
180
181 schema.set_uint(&mut row, 0, &huge);
182 assert!(row.is_defined(0));
183
184 let retrieved = schema.get_uint(&row, 0);
185 assert_eq!(retrieved, huge);
186 }
187
188 #[test]
189 fn test_zero() {
190 let schema = Schema::testing(&[Type::Uint]);
191 let mut row = schema.allocate();
192
193 let zero = Uint::from(0);
194 schema.set_uint(&mut row, 0, &zero);
195 assert!(row.is_defined(0));
196
197 let retrieved = schema.get_uint(&row, 0);
198 assert!(retrieved.is_zero());
199 }
200
201 #[test]
202 fn test_try_get() {
203 let schema = Schema::testing(&[Type::Uint]);
204 let mut row = schema.allocate();
205
206 assert_eq!(schema.try_get_uint(&row, 0), None);
208
209 let value = Uint::from(12345u64);
211 schema.set_uint(&mut row, 0, &value);
212 assert_eq!(schema.try_get_uint(&row, 0), Some(value));
213 }
214
215 #[test]
216 fn test_clone_on_write() {
217 let schema = Schema::testing(&[Type::Uint]);
218 let row1 = schema.allocate();
219 let mut row2 = row1.clone();
220
221 let value = Uint::from(999999999999999u64);
222 schema.set_uint(&mut row2, 0, &value);
223
224 assert!(!row1.is_defined(0));
225 assert!(row2.is_defined(0));
226 assert_ne!(row1.as_ptr(), row2.as_ptr());
227 assert_eq!(schema.get_uint(&row2, 0), value);
228 }
229
230 #[test]
231 fn test_multiple_fields() {
232 let schema = Schema::testing(&[Type::Boolean, Type::Uint, Type::Utf8, Type::Uint, Type::Int4]);
233 let mut row = schema.allocate();
234
235 schema.set_bool(&mut row, 0, true);
236
237 let small = Uint::from(100u64);
238 schema.set_uint(&mut row, 1, &small);
239
240 schema.set_utf8(&mut row, 2, "test");
241
242 let large = Uint::from(u128::MAX >> 1);
243 schema.set_uint(&mut row, 3, &large);
244
245 schema.set_i32(&mut row, 4, 42);
246
247 assert_eq!(schema.get_bool(&row, 0), true);
248 assert_eq!(schema.get_uint(&row, 1), small);
249 assert_eq!(schema.get_utf8(&row, 2), "test");
250 assert_eq!(schema.get_uint(&row, 3), large);
251 assert_eq!(schema.get_i32(&row, 4), 42);
252 }
253
254 #[test]
255 fn test_negative_input_handling() {
256 let schema = Schema::testing(&[Type::Uint]);
257
258 let mut row1 = schema.allocate();
261 let negative = Uint::from(-42); schema.set_uint(&mut row1, 0, &negative);
263
264 let retrieved = schema.get_uint(&row1, 0);
266 assert_eq!(retrieved, Uint::from(0));
267 }
268
269 #[test]
270 fn test_try_get_uint_wrong_type() {
271 let schema = Schema::testing(&[Type::Boolean]);
272 let mut row = schema.allocate();
273
274 schema.set_bool(&mut row, 0, true);
275
276 assert_eq!(schema.try_get_uint(&row, 0), None);
277 }
278}