1use vortex_dtype::{DType, PType};
3use vortex_error::{VortexExpect, VortexResult};
4use vortex_scalar::Scalar;
5
6use crate::arrays::{ConstantArray, PrimitiveArray, PrimitiveEncoding};
7use crate::compute::{min_max, try_cast};
8use crate::vtable::EncodingVTable;
9use crate::{Array, ArrayExt, ArrayRef, ToCanonical};
10
11pub fn downscale_integer_array(array: ArrayRef) -> VortexResult<ArrayRef> {
13 if !array.is_encoding(PrimitiveEncoding.id()) {
14 return Ok(array);
16 }
17 if array.is_empty() {
18 return Ok(array);
19 }
20 let array = array
21 .as_opt::<PrimitiveArray>()
22 .vortex_expect("Checked earlier");
23
24 let Some(min_max) = min_max(array)? else {
25 return Ok(
27 ConstantArray::new(Scalar::null(array.dtype().clone()), array.len()).into_array(),
28 );
29 };
30
31 let Ok(min) = i64::try_from(min_max.min.value()) else {
34 return Ok(array.to_array());
35 };
36 let Ok(max) = i64::try_from(min_max.max.value()) else {
37 return Ok(array.to_array());
38 };
39
40 downscale_primitive_integer_array(array.clone(), min, max).map(|a| a.into_array())
41}
42
43fn downscale_primitive_integer_array(
45 array: PrimitiveArray,
46 min: i64,
47 max: i64,
48) -> VortexResult<PrimitiveArray> {
49 if min < 0 || max < 0 {
50 if min >= i8::MIN as i64 && max <= i8::MAX as i64 {
52 return try_cast(
53 &array,
54 &DType::Primitive(PType::I8, array.dtype().nullability()),
55 )?
56 .to_primitive();
57 }
58
59 if min >= i16::MIN as i64 && max <= i16::MAX as i64 {
60 return try_cast(
61 &array,
62 &DType::Primitive(PType::I16, array.dtype().nullability()),
63 )?
64 .to_primitive();
65 }
66
67 if min >= i32::MIN as i64 && max <= i32::MAX as i64 {
68 return try_cast(
69 &array,
70 &DType::Primitive(PType::I32, array.dtype().nullability()),
71 )?
72 .to_primitive();
73 }
74 } else {
75 if max <= u8::MAX as i64 {
77 return try_cast(
78 &array,
79 &DType::Primitive(PType::U8, array.dtype().nullability()),
80 )?
81 .to_primitive();
82 }
83
84 if max <= u16::MAX as i64 {
85 return try_cast(
86 &array,
87 &DType::Primitive(PType::U16, array.dtype().nullability()),
88 )?
89 .to_primitive();
90 }
91
92 if max <= u32::MAX as i64 {
93 return try_cast(
94 &array,
95 &DType::Primitive(PType::U32, array.dtype().nullability()),
96 )?
97 .to_primitive();
98 }
99 }
100
101 Ok(array)
102}