vortex_array/arrays/decimal/
utils.rs1use itertools::Itertools;
5use itertools::MinMaxResult;
6use vortex_buffer::Buffer;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_mask::Mask;
11
12use crate::arrays::DecimalArray;
13use crate::arrays::decimal::DecimalArrayExt;
14use crate::dtype::DecimalType;
15use crate::dtype::NativeDecimalType;
16use crate::dtype::i256;
17use crate::match_each_decimal_value_type;
18
19pub(crate) fn widened_buffer<W: NativeDecimalType>(array: &DecimalArray) -> Buffer<W> {
22 if array.values_type() == W::DECIMAL_TYPE {
23 return array.buffer::<W>();
24 }
25 match_each_decimal_value_type!(array.values_type(), |T| {
26 array
27 .buffer::<T>()
28 .iter()
29 .map(|v| W::from(*v).vortex_expect("widening decimal cast must succeed"))
30 .collect()
31 })
32}
33
34pub fn converted_buffer<W: NativeDecimalType>(
41 array: &DecimalArray,
42 validity: &Mask,
43) -> VortexResult<Buffer<W>> {
44 if array.values_type() <= W::DECIMAL_TYPE {
46 return Ok(widened_buffer(array));
47 }
48 match_each_decimal_value_type!(array.values_type(), |T| {
49 let src = array.buffer::<T>();
50 match validity {
51 Mask::AllTrue(_) => {
52 let any_overflow = src.iter().fold(false, |acc, v| acc | W::from(*v).is_none());
55 if any_overflow {
56 let (i, v) = src
57 .iter()
58 .enumerate()
59 .find(|&(_, v)| W::from(*v).is_none())
60 .vortex_expect("overflow scan found an overflowing value");
61 vortex_bail!(
62 "decimal value {v} at index {i} does not fit {}",
63 W::DECIMAL_TYPE
64 );
65 }
66 }
67 Mask::AllFalse(_) => return Ok(Buffer::zeroed(src.len())),
68 Mask::Values(values) => {
69 let any_overflow = src.iter().fold(false, |acc, v| acc | W::from(*v).is_none());
70 if any_overflow {
71 for (i, v) in src.iter().enumerate() {
72 if values.value(i) && W::from(*v).is_none() {
73 vortex_bail!(
74 "decimal value {v} at index {i} does not fit {}",
75 W::DECIMAL_TYPE
76 );
77 }
78 }
79 }
80 }
81 }
82 Ok(src
85 .iter()
86 .map(|v| W::from(*v).unwrap_or_default())
87 .collect())
88 })
89}
90
91macro_rules! try_downcast {
92 ($array:expr, from: $src:ty, to: $($dst:ty),*) => {{
93 use crate::dtype::BigCast;
94
95 let minmax = $array.buffer::<$src>().iter().copied().minmax();
97 match minmax {
98 MinMaxResult::NoElements => return $array,
99 MinMaxResult::OneElement(_) => return $array,
100 MinMaxResult::MinMax(min, max) => {
101 $(
102 if <$dst as BigCast>::from(min).is_some() && <$dst as BigCast>::from(max).is_some() {
103 return DecimalArray::new::<$dst>(
104 $array
105 .buffer::<$src>()
106 .into_iter()
107 .map(|v| <$dst as BigCast>::from(v).vortex_expect("decimal conversion failure"))
108 .collect(),
109 $array.decimal_dtype(),
110 $array
111 .validity()
112 .vortex_expect("decimal validity should be derivable"),
113 );
114 }
115 )*
116
117 return $array;
118 }
119 }
120 }};
121}
122
123pub fn narrowed_decimal(decimal_array: DecimalArray) -> DecimalArray {
125 match decimal_array.values_type() {
126 DecimalType::I8 => decimal_array,
128 DecimalType::I16 => {
129 try_downcast!(decimal_array, from: i16, to: i8)
130 }
131 DecimalType::I32 => {
132 try_downcast!(decimal_array, from: i32, to: i8, i16)
133 }
134 DecimalType::I64 => {
135 try_downcast!(decimal_array, from: i64, to: i8, i16, i32)
136 }
137 DecimalType::I128 => {
138 try_downcast!(decimal_array, from: i128, to: i8, i16, i32, i64)
139 }
140 DecimalType::I256 => {
141 try_downcast!(decimal_array, from: i256, to: i8, i16, i32, i64, i128)
142 }
143 }
144}