vortex_array/vtable/
validity.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6use vortex_error::vortex_panic;
7use vortex_mask::Mask;
8
9use crate::Array;
10use crate::ArrayRef;
11use crate::validity::Validity;
12use crate::vtable::NotSupported;
13use crate::vtable::VTable;
14
15pub trait ValidityVTable<V: VTable> {
16    fn is_valid(array: &V::Array, index: usize) -> bool;
17
18    fn all_valid(array: &V::Array) -> bool;
19
20    fn all_invalid(array: &V::Array) -> bool;
21
22    /// Returns the number of valid elements in the array.
23    ///
24    /// ## Post-conditions
25    /// - The count is less than or equal to the length of the array.
26    fn valid_count(array: &V::Array) -> usize {
27        Self::validity_mask(array).true_count()
28    }
29
30    /// Returns the number of invalid elements in the array.
31    ///
32    /// ## Post-conditions
33    /// - The count is less than or equal to the length of the array.
34    fn invalid_count(array: &V::Array) -> usize {
35        Self::validity_mask(array).false_count()
36    }
37
38    /// Returns the [`Validity`] of the array.
39    ///
40    /// ## Pre-conditions
41    ///
42    /// - The array DType is nullable.
43    fn validity(array: &V::Array) -> VortexResult<Validity>;
44
45    fn validity_mask(array: &V::Array) -> Mask {
46        Self::validity(array)
47            .vortex_expect("TODO: make this fallible")
48            .to_mask(array.len())
49    }
50}
51
52impl<V: VTable> ValidityVTable<V> for NotSupported {
53    fn is_valid(array: &V::Array, _index: usize) -> bool {
54        vortex_panic!(
55            "Legacy is_valid is not supported for {} arrays",
56            array.encoding_id()
57        )
58    }
59
60    fn all_valid(array: &V::Array) -> bool {
61        vortex_panic!(
62            "Legacy all_valid is not supported for {} arrays",
63            array.encoding_id()
64        )
65    }
66
67    fn all_invalid(array: &V::Array) -> bool {
68        vortex_panic!(
69            "Legacy all_invalid is not supported for {} arrays",
70            array.encoding_id()
71        )
72    }
73
74    fn validity(array: &V::Array) -> VortexResult<Validity> {
75        vortex_panic!(
76            "Legacy validity is not supported for {} arrays",
77            array.encoding_id()
78        )
79    }
80}
81
82/// An implementation of the [`ValidityVTable`] for arrays that hold validity as a child array.
83pub struct ValidityVTableFromValidityHelper;
84
85/// Expose validity held as a child array.
86pub trait ValidityHelper {
87    fn validity(&self) -> &Validity;
88}
89
90impl<V: VTable> ValidityVTable<V> for ValidityVTableFromValidityHelper
91where
92    V::Array: ValidityHelper,
93{
94    fn is_valid(array: &V::Array, index: usize) -> bool {
95        array.validity().is_valid(index)
96    }
97
98    fn all_valid(array: &V::Array) -> bool {
99        array.validity().all_valid(array.len())
100    }
101
102    fn all_invalid(array: &V::Array) -> bool {
103        array.validity().all_invalid(array.len())
104    }
105
106    fn validity(array: &V::Array) -> VortexResult<Validity> {
107        Ok(array.validity().clone())
108    }
109}
110
111/// An implementation of the [`ValidityVTable`] for arrays that hold an unsliced validity
112/// and a slice into it.
113pub struct ValidityVTableFromValiditySliceHelper;
114
115pub trait ValiditySliceHelper {
116    fn unsliced_validity_and_slice(&self) -> (&Validity, usize, usize);
117
118    fn sliced_validity(&self) -> Validity {
119        let (unsliced_validity, start, stop) = self.unsliced_validity_and_slice();
120        unsliced_validity.slice(start..stop)
121    }
122}
123
124impl<V: VTable> ValidityVTable<V> for ValidityVTableFromValiditySliceHelper
125where
126    V::Array: ValiditySliceHelper,
127{
128    fn is_valid(array: &V::Array, index: usize) -> bool {
129        let (unsliced_validity, start, _) = array.unsliced_validity_and_slice();
130        unsliced_validity.is_valid(start + index)
131    }
132
133    fn all_valid(array: &V::Array) -> bool {
134        array.sliced_validity().all_valid(array.len())
135    }
136
137    fn all_invalid(array: &V::Array) -> bool {
138        array.sliced_validity().all_invalid(array.len())
139    }
140
141    fn validity(array: &V::Array) -> VortexResult<Validity> {
142        Ok(array.sliced_validity())
143    }
144}
145
146/// An implementation of the [`ValidityVTable`] for arrays that delegate validity entirely
147/// to a child array.
148pub struct ValidityVTableFromChild;
149
150pub trait ValidityChild<V: VTable> {
151    fn validity_child(array: &V::Array) -> &ArrayRef;
152}
153
154impl<V: VTable> ValidityVTable<V> for ValidityVTableFromChild
155where
156    V: ValidityChild<V>,
157{
158    fn is_valid(array: &V::Array, index: usize) -> bool {
159        V::validity_child(array).is_valid(index)
160    }
161
162    fn all_valid(array: &V::Array) -> bool {
163        V::validity_child(array).all_valid()
164    }
165
166    fn all_invalid(array: &V::Array) -> bool {
167        V::validity_child(array).all_invalid()
168    }
169
170    fn validity(array: &V::Array) -> VortexResult<Validity> {
171        Ok(Validity::Array(V::validity_child(array).to_array()))
172    }
173
174    fn validity_mask(array: &V::Array) -> Mask {
175        V::validity_child(array).validity_mask()
176    }
177}
178
179/// An implementation of the [`ValidityVTable`] for arrays that hold an unsliced validity
180/// and a slice into it.
181pub struct ValidityVTableFromChildSliceHelper;
182
183pub trait ValidityChildSliceHelper {
184    fn unsliced_child_and_slice(&self) -> (&ArrayRef, usize, usize);
185
186    fn sliced_child_array(&self) -> ArrayRef {
187        let (unsliced_validity, start, stop) = self.unsliced_child_and_slice();
188        unsliced_validity.slice(start..stop)
189    }
190}
191
192impl<V: VTable> ValidityVTable<V> for ValidityVTableFromChildSliceHelper
193where
194    V::Array: ValidityChildSliceHelper,
195{
196    fn is_valid(array: &V::Array, index: usize) -> bool {
197        let (unsliced_validity, start, _) = array.unsliced_child_and_slice();
198        unsliced_validity.is_valid(start + index)
199    }
200
201    fn all_valid(array: &V::Array) -> bool {
202        array.sliced_child_array().all_valid()
203    }
204
205    fn all_invalid(array: &V::Array) -> bool {
206        array.sliced_child_array().all_invalid()
207    }
208
209    fn validity(array: &V::Array) -> VortexResult<Validity> {
210        array.sliced_child_array().validity()
211    }
212}