1use std::any::Any;
5
6use vortex_buffer::BufferAllocatorRef;
7use vortex_buffer::BufferMut;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_ensure;
11use vortex_error::vortex_err;
12use vortex_error::vortex_panic;
13
14use crate::ArrayRef;
15use crate::ExecutionCtx;
16use crate::IntoArray;
17use crate::arrays::DecimalArray;
18use crate::builders::ArrayBuilder;
19use crate::builders::DEFAULT_BUILDER_CAPACITY;
20use crate::builders::LazyBitBufferBuilder;
21use crate::canonical::Canonical;
22use crate::dtype::BigCast;
23use crate::dtype::DType;
24use crate::dtype::DecimalDType;
25use crate::dtype::NativeDecimalType;
26use crate::dtype::Nullability;
27use crate::dtype::i256;
28use crate::match_each_decimal_value;
29use crate::match_each_decimal_value_type;
30use crate::scalar::DecimalValue;
31use crate::scalar::Scalar;
32
33pub struct DecimalBuilder {
39 dtype: DType,
40 values: DecimalBuffer,
41 nulls: LazyBitBufferBuilder,
42}
43
44enum DecimalBuffer {
50 I8(BufferMut<i8>),
51 I16(BufferMut<i16>),
52 I32(BufferMut<i32>),
53 I64(BufferMut<i64>),
54 I128(BufferMut<i128>),
55 I256(BufferMut<i256>),
56}
57
58macro_rules! delegate_fn {
59 ($self:expr, | $tname:ident, $buffer:ident | $body:block) => {{
60 #[allow(unused)]
61 match $self {
62 DecimalBuffer::I8(buffer) => {
63 type $tname = i8;
64 let $buffer = buffer;
65 $body
66 }
67 DecimalBuffer::I16(buffer) => {
68 type $tname = i16;
69 let $buffer = buffer;
70 $body
71 }
72 DecimalBuffer::I32(buffer) => {
73 type $tname = i32;
74 let $buffer = buffer;
75 $body
76 }
77 DecimalBuffer::I64(buffer) => {
78 type $tname = i64;
79 let $buffer = buffer;
80 $body
81 }
82 DecimalBuffer::I128(buffer) => {
83 type $tname = i128;
84 let $buffer = buffer;
85 $body
86 }
87 DecimalBuffer::I256(buffer) => {
88 type $tname = i256;
89 let $buffer = buffer;
90 $body
91 }
92 }
93 }};
94}
95
96impl DecimalBuilder {
97 #[deprecated(note = "use `new_in` with an explicit allocator")]
99 pub fn new<T: NativeDecimalType>(decimal: DecimalDType, nullability: Nullability) -> Self {
100 Self::new_in::<T>(decimal, nullability, BufferAllocatorRef::static_ref())
101 }
102
103 pub fn new_in<T: NativeDecimalType>(
105 decimal: DecimalDType,
106 nullability: Nullability,
107 allocator: &BufferAllocatorRef,
108 ) -> Self {
109 Self::with_capacity_in::<T>(DEFAULT_BUILDER_CAPACITY, decimal, nullability, allocator)
110 }
111
112 #[deprecated(note = "use `with_capacity_in` with an explicit allocator")]
114 pub fn with_capacity<T: NativeDecimalType>(
115 capacity: usize,
116 decimal: DecimalDType,
117 nullability: Nullability,
118 ) -> Self {
119 Self::with_capacity_in::<T>(
120 capacity,
121 decimal,
122 nullability,
123 BufferAllocatorRef::static_ref(),
124 )
125 }
126
127 pub fn with_capacity_in<T: NativeDecimalType>(
129 capacity: usize,
130 decimal: DecimalDType,
131 nullability: Nullability,
132 allocator: &BufferAllocatorRef,
133 ) -> Self {
134 Self {
135 dtype: DType::Decimal(decimal, nullability),
136 values: match_each_decimal_value_type!(T::DECIMAL_TYPE, |D| {
137 DecimalBuffer::from(BufferMut::<D>::with_capacity_in(
138 capacity,
139 allocator.clone(),
140 ))
141 }),
142 nulls: LazyBitBufferBuilder::new(capacity, allocator.clone()),
143 }
144 }
145
146 pub fn append_value<V: NativeDecimalType>(&mut self, value: V) {
148 self.values.push(value);
149 self.nulls.append_non_null();
150 }
151
152 pub fn append_n_values<V: NativeDecimalType>(&mut self, value: V, n: usize) {
154 self.values.push_n(value, n);
155 self.nulls.append_n_non_nulls(n);
156 }
157
158 pub(crate) fn append_decimal_array(
161 &mut self,
162 array: &DecimalArray,
163 ctx: &mut ExecutionCtx,
164 ) -> VortexResult<()> {
165 match_each_decimal_value_type!(array.values_type(), |D| {
166 self.values.extend(array.buffer::<D>().iter().copied());
169 });
170
171 self.nulls.append_validity_mask(
172 &array
173 .as_ref()
174 .validity()?
175 .execute_mask(array.as_ref().len(), ctx)?,
176 );
177 Ok(())
178 }
179
180 pub fn finish_into_decimal(&mut self) -> DecimalArray {
182 let validity = self.nulls.finish_with_nullability(self.dtype.nullability());
183
184 let decimal_dtype = *self.decimal_dtype();
185
186 delegate_fn!(self.values.take(), |T, values| {
187 DecimalArray::new::<T>(values.freeze(), decimal_dtype, validity)
188 })
189 }
190
191 pub fn decimal_dtype(&self) -> &DecimalDType {
193 let DType::Decimal(decimal_dtype, _) = &self.dtype else {
194 vortex_panic!("`DecimalBuilder` somehow had dtype {}", self.dtype);
195 };
196
197 decimal_dtype
198 }
199}
200
201impl ArrayBuilder for DecimalBuilder {
202 fn as_any(&self) -> &dyn Any {
203 self
204 }
205
206 fn as_any_mut(&mut self) -> &mut dyn Any {
207 self
208 }
209
210 fn dtype(&self) -> &DType {
211 &self.dtype
212 }
213
214 fn len(&self) -> usize {
215 self.values.len()
216 }
217
218 fn append_zeros(&mut self, n: usize) {
219 self.values.push_n(0, n);
220 self.nulls.append_n_non_nulls(n);
221 }
222
223 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
224 self.values.push_n(0, n);
225 self.nulls.append_n_nulls(n);
226 }
227
228 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
229 vortex_ensure!(
230 scalar.dtype() == self.dtype(),
231 "DecimalBuilder expected scalar with dtype {}, got {}",
232 self.dtype(),
233 scalar.dtype()
234 );
235
236 match scalar.as_decimal().decimal_value() {
237 None => self.append_null(),
238 Some(v) => match_each_decimal_value!(v, |dec_val| {
239 self.append_value(dec_val);
240 }),
241 }
242
243 Ok(())
244 }
245
246 fn reserve_exact(&mut self, additional: usize) {
247 self.values.reserve(additional);
248 self.nulls.reserve_exact(additional);
249 }
250
251 fn finish(&mut self) -> ArrayRef {
252 self.finish_into_decimal().into_array()
253 }
254
255 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
256 Canonical::Decimal(self.finish_into_decimal())
257 }
258}
259
260impl DecimalBuffer {
261 fn take(&mut self) -> Self {
262 delegate_fn!(self, |T, buffer| { DecimalBuffer::from(buffer.take()) })
263 }
264
265 fn push<V: NativeDecimalType>(&mut self, value: V) {
266 delegate_fn!(self, |T, buffer| {
267 buffer.push(
268 <T as BigCast>::from(value)
269 .ok_or_else(|| {
270 vortex_err!(
271 "decimal conversion failure {:?}, type: {:?} to {:?}",
272 value,
273 V::DECIMAL_TYPE,
274 T::DECIMAL_TYPE,
275 )
276 })
277 .vortex_expect("operation should succeed in builder"),
278 )
279 });
280 }
281
282 fn push_n<V: NativeDecimalType>(&mut self, value: V, n: usize) {
283 delegate_fn!(self, |T, buffer| {
284 buffer.push_n(
285 <T as BigCast>::from(value).vortex_expect("decimal conversion failure"),
286 n,
287 )
288 });
289 }
290
291 fn reserve(&mut self, additional: usize) {
292 delegate_fn!(self, |T, buffer| { buffer.reserve(additional) })
293 }
294
295 fn len(&self) -> usize {
296 delegate_fn!(self, |T, buffer| { buffer.len() })
297 }
298
299 pub fn extend<I, V: NativeDecimalType>(&mut self, iter: I)
300 where
301 I: Iterator<Item = V>,
302 {
303 delegate_fn!(self, |T, buffer| {
304 buffer.extend(
305 iter.map(|x| <T as BigCast>::from(x).vortex_expect("decimal conversion failure")),
306 )
307 })
308 }
309}
310
311macro_rules! impl_from_buffer {
312 ($T:ty, $variant:ident) => {
313 impl From<BufferMut<$T>> for DecimalBuffer {
314 fn from(buffer: BufferMut<$T>) -> Self {
315 Self::$variant(buffer)
316 }
317 }
318 };
319}
320
321impl_from_buffer!(i8, I8);
322impl_from_buffer!(i16, I16);
323impl_from_buffer!(i32, I32);
324impl_from_buffer!(i64, I64);
325impl_from_buffer!(i128, I128);
326impl_from_buffer!(i256, I256);
327
328#[cfg(test)]
329mod tests {
330 use vortex_buffer::BufferAllocatorRef;
331
332 use crate::VortexSessionExecute;
333 use crate::array_session;
334 use crate::assert_arrays_eq;
335 use crate::builders::ArrayBuilder;
336 use crate::builders::DecimalBuilder;
337 use crate::builders::decimal::DecimalArray;
338 use crate::dtype::DecimalDType;
339
340 #[test]
341 fn test_mixed_extend() {
342 let values = 42i8;
343
344 let mut i8s = DecimalBuilder::new_in::<i8>(
345 DecimalDType::new(2, 1),
346 false.into(),
347 BufferAllocatorRef::static_ref(),
348 );
349 for v in 0..values {
350 i8s.append_value(v);
351 }
352 let i8s = i8s.finish();
353
354 let mut i128s = DecimalBuilder::new_in::<i128>(
355 DecimalDType::new(2, 1),
356 false.into(),
357 BufferAllocatorRef::static_ref(),
358 );
359 i8s.append_to_builder(&mut i128s, &mut array_session().create_execution_ctx())
360 .unwrap();
361 let i128s = i128s.finish();
362
363 for i in 0..i8s.len() {
364 assert_eq!(
365 i8s.execute_scalar(i, &mut array_session().create_execution_ctx())
366 .unwrap(),
367 i128s
368 .execute_scalar(i, &mut array_session().create_execution_ctx())
369 .unwrap()
370 );
371 }
372 }
373
374 #[test]
375 fn test_append_scalar() {
376 let mut ctx = array_session().create_execution_ctx();
377 use crate::scalar::Scalar;
378
379 let mut builder = DecimalBuilder::new_in::<i64>(
381 DecimalDType::new(10, 2),
382 true.into(),
383 BufferAllocatorRef::static_ref(),
384 );
385 builder.append_value(1234i64);
386 builder.append_value(5678i64);
387 builder.append_null();
388
389 let array = builder.finish();
390 let expected = DecimalArray::from_option_iter(
391 [Some(1234i64), Some(5678), None],
392 DecimalDType::new(10, 2),
393 );
394 assert_arrays_eq!(&array, &expected, &mut ctx);
395
396 let mut builder2 = DecimalBuilder::new_in::<i64>(
398 DecimalDType::new(10, 2),
399 true.into(),
400 BufferAllocatorRef::static_ref(),
401 );
402 for i in 0..array.len() {
403 let scalar = array
404 .execute_scalar(i, &mut array_session().create_execution_ctx())
405 .unwrap();
406 builder2.append_scalar(&scalar).unwrap();
407 }
408
409 let array2 = builder2.finish();
410 assert_arrays_eq!(&array2, &array, &mut ctx);
411
412 let mut builder = DecimalBuilder::new_in::<i64>(
414 DecimalDType::new(10, 2),
415 false.into(),
416 BufferAllocatorRef::static_ref(),
417 );
418 let wrong_scalar = Scalar::from(true);
419 assert!(builder.append_scalar(&wrong_scalar).is_err());
420 }
421}