1use std::any::Any;
5
6use vortex_buffer::BufferMut;
7use vortex_dtype::{DType, DecimalDType, Nullability};
8use vortex_error::{VortexExpect, vortex_panic};
9use vortex_mask::Mask;
10use vortex_scalar::{BigCast, NativeDecimalType, i256, match_each_decimal_value_type};
11
12use crate::arrays::DecimalArray;
13use crate::builders::{ArrayBuilder, DEFAULT_BUILDER_CAPACITY, LazyNullBufferBuilder};
14use crate::canonical::Canonical;
15use crate::{Array, ArrayRef, IntoArray, ToCanonical};
16
17pub struct DecimalBuilder {
23 dtype: DType,
24 values: DecimalBuffer,
25 nulls: LazyNullBufferBuilder,
26}
27
28enum DecimalBuffer {
34 I8(BufferMut<i8>),
35 I16(BufferMut<i16>),
36 I32(BufferMut<i32>),
37 I64(BufferMut<i64>),
38 I128(BufferMut<i128>),
39 I256(BufferMut<i256>),
40}
41
42macro_rules! delegate_fn {
43 ($self:expr, | $tname:ident, $buffer:ident | $body:block) => {{
44 #[allow(unused)]
45 match $self {
46 DecimalBuffer::I8(buffer) => {
47 type $tname = i8;
48 let $buffer = buffer;
49 $body
50 }
51 DecimalBuffer::I16(buffer) => {
52 type $tname = i16;
53 let $buffer = buffer;
54 $body
55 }
56 DecimalBuffer::I32(buffer) => {
57 type $tname = i32;
58 let $buffer = buffer;
59 $body
60 }
61 DecimalBuffer::I64(buffer) => {
62 type $tname = i64;
63 let $buffer = buffer;
64 $body
65 }
66 DecimalBuffer::I128(buffer) => {
67 type $tname = i128;
68 let $buffer = buffer;
69 $body
70 }
71 DecimalBuffer::I256(buffer) => {
72 type $tname = i256;
73 let $buffer = buffer;
74 $body
75 }
76 }
77 }};
78}
79
80impl DecimalBuilder {
81 pub fn new<T: NativeDecimalType>(precision: u8, scale: i8, nullability: Nullability) -> Self {
83 Self::with_capacity::<T>(
84 DEFAULT_BUILDER_CAPACITY,
85 DecimalDType::new(precision, scale),
86 nullability,
87 )
88 }
89
90 pub fn with_capacity<T: NativeDecimalType>(
92 capacity: usize,
93 decimal: DecimalDType,
94 nullability: Nullability,
95 ) -> Self {
96 Self {
97 dtype: DType::Decimal(decimal, nullability),
98 values: match_each_decimal_value_type!(T::VALUES_TYPE, |D| {
99 DecimalBuffer::from(BufferMut::<D>::with_capacity(capacity))
100 }),
101 nulls: LazyNullBufferBuilder::new(capacity),
102 }
103 }
104
105 pub fn append_value<V: NativeDecimalType>(&mut self, value: V) {
107 self.values.push(value);
108 self.nulls.append_non_null();
109 }
110
111 pub fn append_option<V: NativeDecimalType>(&mut self, value: Option<V>) {
120 match value {
121 Some(value) => self.append_value(value),
122 None => self.append_null(),
123 }
124 }
125
126 pub fn finish_into_decimal(&mut self) -> DecimalArray {
128 let validity = self.nulls.finish_with_nullability(self.dtype.nullability());
129
130 let decimal_dtype = *self.decimal_dtype();
131
132 delegate_fn!(std::mem::take(&mut self.values), |T, values| {
133 DecimalArray::new::<T>(values.freeze(), decimal_dtype, validity)
134 })
135 }
136
137 pub fn decimal_dtype(&self) -> &DecimalDType {
139 let DType::Decimal(decimal_dtype, _) = &self.dtype else {
140 vortex_panic!("`DecimalBuilder` somehow had dtype {}", self.dtype);
141 };
142
143 decimal_dtype
144 }
145}
146
147impl ArrayBuilder for DecimalBuilder {
148 fn as_any(&self) -> &dyn Any {
149 self
150 }
151
152 fn as_any_mut(&mut self) -> &mut dyn Any {
153 self
154 }
155
156 fn dtype(&self) -> &DType {
157 &self.dtype
158 }
159
160 fn len(&self) -> usize {
161 self.values.len()
162 }
163
164 fn append_zeros(&mut self, n: usize) {
165 self.values.push_n(0, n);
166 self.nulls.append_n_non_nulls(n);
167 }
168
169 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
170 self.values.push_n(0, n);
171 self.nulls.append_n_nulls(n);
172 }
173
174 unsafe fn extend_from_array_unchecked(&mut self, array: &dyn Array) {
175 let decimal_array = array.to_decimal();
176
177 match_each_decimal_value_type!(decimal_array.values_type(), |D| {
178 self.values
181 .extend(decimal_array.buffer::<D>().iter().copied());
182 });
183
184 self.nulls
185 .append_validity_mask(decimal_array.validity_mask());
186 }
187
188 fn ensure_capacity(&mut self, capacity: usize) {
189 if capacity > self.values.capacity() {
190 self.values.reserve(capacity - self.values.len());
191 self.nulls.ensure_capacity(capacity);
192 }
193 }
194
195 fn set_validity(&mut self, validity: Mask) {
196 self.nulls = LazyNullBufferBuilder::new(validity.len());
197 self.nulls.append_validity_mask(validity);
198 }
199
200 fn finish(&mut self) -> ArrayRef {
201 self.finish_into_decimal().into_array()
202 }
203
204 fn finish_into_canonical(&mut self) -> Canonical {
205 Canonical::Decimal(self.finish_into_decimal())
206 }
207}
208
209impl DecimalBuffer {
210 fn push<V: NativeDecimalType>(&mut self, value: V) {
211 delegate_fn!(self, |T, buffer| {
212 buffer.push(<T as BigCast>::from(value).vortex_expect("decimal conversion failure"))
213 });
214 }
215
216 fn push_n<V: NativeDecimalType>(&mut self, value: V, n: usize) {
217 delegate_fn!(self, |T, buffer| {
218 buffer.push_n(
219 <T as BigCast>::from(value).vortex_expect("decimal conversion failure"),
220 n,
221 )
222 });
223 }
224
225 fn reserve(&mut self, additional: usize) {
226 delegate_fn!(self, |T, buffer| { buffer.reserve(additional) })
227 }
228
229 fn capacity(&self) -> usize {
230 delegate_fn!(self, |T, buffer| { buffer.capacity() })
231 }
232
233 fn len(&self) -> usize {
234 delegate_fn!(self, |T, buffer| { buffer.len() })
235 }
236
237 pub fn extend<I, V: NativeDecimalType>(&mut self, iter: I)
238 where
239 I: Iterator<Item = V>,
240 {
241 delegate_fn!(self, |T, buffer| {
242 buffer.extend(
243 iter.map(|x| <T as BigCast>::from(x).vortex_expect("decimal conversion failure")),
244 )
245 })
246 }
247}
248
249macro_rules! impl_from_buffer {
250 ($T:ty, $variant:ident) => {
251 impl From<BufferMut<$T>> for DecimalBuffer {
252 fn from(buffer: BufferMut<$T>) -> Self {
253 Self::$variant(buffer)
254 }
255 }
256 };
257}
258
259impl_from_buffer!(i8, I8);
260impl_from_buffer!(i16, I16);
261impl_from_buffer!(i32, I32);
262impl_from_buffer!(i64, I64);
263impl_from_buffer!(i128, I128);
264impl_from_buffer!(i256, I256);
265
266impl Default for DecimalBuffer {
267 fn default() -> Self {
268 Self::I8(BufferMut::<i8>::empty())
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use crate::builders::{ArrayBuilder, DecimalBuilder};
275
276 #[test]
277 fn test_mixed_extend() {
278 let values = 42i8;
279
280 let mut i8s = DecimalBuilder::new::<i8>(2, 1, false.into());
281 for v in 0..values {
282 i8s.append_value(v);
283 }
284 let i8s = i8s.finish();
285
286 let mut i128s = DecimalBuilder::new::<i128>(2, 1, false.into());
287 i128s.extend_from_array(&i8s);
288 let i128s = i128s.finish();
289
290 for i in 0..i8s.len() {
291 assert_eq!(i8s.scalar_at(i), i128s.scalar_at(i));
292 }
293 }
294}