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