vortex_array/arrays/null/
compute.rs1use arrow_array::{ArrayRef as ArrowArrayRef, new_null_array};
2use arrow_schema::DataType;
3use vortex_dtype::{DType, match_each_integer_ptype};
4use vortex_error::{VortexResult, vortex_bail};
5use vortex_mask::Mask;
6use vortex_scalar::Scalar;
7
8use crate::arrays::NullEncoding;
9use crate::arrays::null::NullArray;
10use crate::compute::{
11 FilterKernel, FilterKernelAdapter, KernelRef, MaskFn, MinMaxFn, MinMaxResult, ScalarAtFn,
12 SliceFn, TakeFn, ToArrowFn, UncompressedSizeFn,
13};
14use crate::nbytes::NBytes;
15use crate::variants::PrimitiveArrayTrait;
16use crate::vtable::ComputeVTable;
17use crate::{Array, ArrayComputeImpl, ArrayRef, ToCanonical};
18
19impl ArrayComputeImpl for NullArray {
20 const FILTER: Option<KernelRef> = FilterKernelAdapter(NullEncoding).some();
21}
22
23impl ComputeVTable for NullEncoding {
24 fn mask_fn(&self) -> Option<&dyn MaskFn<&dyn Array>> {
25 Some(self)
26 }
27
28 fn scalar_at_fn(&self) -> Option<&dyn ScalarAtFn<&dyn Array>> {
29 Some(self)
30 }
31
32 fn slice_fn(&self) -> Option<&dyn SliceFn<&dyn Array>> {
33 Some(self)
34 }
35
36 fn take_fn(&self) -> Option<&dyn TakeFn<&dyn Array>> {
37 Some(self)
38 }
39
40 fn to_arrow_fn(&self) -> Option<&dyn ToArrowFn<&dyn Array>> {
41 Some(self)
42 }
43
44 fn min_max_fn(&self) -> Option<&dyn MinMaxFn<&dyn Array>> {
45 Some(self)
46 }
47
48 fn uncompressed_size_fn(&self) -> Option<&dyn UncompressedSizeFn<&dyn Array>> {
49 Some(self)
50 }
51}
52
53impl FilterKernel for NullEncoding {
54 fn filter(&self, _array: &Self::Array, mask: &Mask) -> VortexResult<ArrayRef> {
55 Ok(NullArray::new(mask.true_count()).into_array())
56 }
57}
58
59impl MaskFn<&NullArray> for NullEncoding {
60 fn mask(&self, array: &NullArray, _mask: Mask) -> VortexResult<ArrayRef> {
61 Ok(array.to_array().into_array())
62 }
63}
64
65impl SliceFn<&NullArray> for NullEncoding {
66 fn slice(&self, _array: &NullArray, start: usize, stop: usize) -> VortexResult<ArrayRef> {
67 Ok(NullArray::new(stop - start).into_array())
68 }
69}
70
71impl ScalarAtFn<&NullArray> for NullEncoding {
72 fn scalar_at(&self, _array: &NullArray, _index: usize) -> VortexResult<Scalar> {
73 Ok(Scalar::null(DType::Null))
74 }
75}
76
77impl TakeFn<&NullArray> for NullEncoding {
78 fn take(&self, array: &NullArray, indices: &dyn Array) -> VortexResult<ArrayRef> {
79 let indices = indices.to_primitive()?;
80
81 match_each_integer_ptype!(indices.ptype(), |$T| {
83 for index in indices.as_slice::<$T>() {
84 if !((*index as usize) < array.len()) {
85 vortex_bail!(OutOfBounds: *index as usize, 0, array.len());
86 }
87 }
88 });
89
90 Ok(NullArray::new(indices.len()).into_array())
91 }
92}
93
94impl ToArrowFn<&NullArray> for NullEncoding {
95 fn to_arrow(
96 &self,
97 array: &NullArray,
98 data_type: &DataType,
99 ) -> VortexResult<Option<ArrowArrayRef>> {
100 if data_type != &DataType::Null {
101 vortex_bail!("Unsupported data type: {data_type}");
102 }
103 Ok(Some(new_null_array(data_type, array.len())))
104 }
105}
106
107impl MinMaxFn<&NullArray> for NullEncoding {
108 fn min_max(&self, _array: &NullArray) -> VortexResult<Option<MinMaxResult>> {
109 Ok(None)
110 }
111}
112
113impl UncompressedSizeFn<&NullArray> for NullEncoding {
114 fn uncompressed_size(&self, array: &NullArray) -> VortexResult<usize> {
115 Ok(array.nbytes())
116 }
117}
118
119#[cfg(test)]
120mod test {
121 use vortex_buffer::buffer;
122 use vortex_dtype::DType;
123 use vortex_mask::Mask;
124
125 use crate::array::Array;
126 use crate::arrays::null::NullArray;
127 use crate::compute::{scalar_at, slice, take};
128 use crate::{ArrayExt, IntoArray};
129
130 #[test]
131 fn test_slice_nulls() {
132 let nulls = NullArray::new(10);
133 let sliced = slice(&nulls, 0, 4).unwrap().as_::<NullArray>().clone();
134
135 assert_eq!(sliced.len(), 4);
136 assert!(matches!(sliced.validity_mask().unwrap(), Mask::AllFalse(4)));
137 }
138
139 #[test]
140 fn test_take_nulls() {
141 let nulls = NullArray::new(10);
142 let taken = take(&nulls, &buffer![0u64, 2, 4, 6, 8].into_array())
143 .unwrap()
144 .as_::<NullArray>()
145 .clone();
146
147 assert_eq!(taken.len(), 5);
148 assert!(matches!(taken.validity_mask().unwrap(), Mask::AllFalse(5)));
149 }
150
151 #[test]
152 fn test_scalar_at_nulls() {
153 let nulls = NullArray::new(10);
154
155 let scalar = scalar_at(&nulls, 0).unwrap();
156 assert!(scalar.is_null());
157 assert_eq!(scalar.dtype().clone(), DType::Null);
158 }
159}