Skip to main content

vortex_array/arrays/null/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use vortex_error::VortexResult;
5use vortex_error::vortex_bail;
6use vortex_error::vortex_ensure;
7use vortex_error::vortex_ensure_eq;
8use vortex_error::vortex_panic;
9use vortex_session::VortexSession;
10use vortex_session::registry::CachedId;
11
12use crate::ArrayRef;
13use crate::ArraySlots;
14use crate::ArrayVTable;
15use crate::ExecutionCtx;
16use crate::ExecutionResult;
17use crate::array::Array;
18use crate::array::ArrayId;
19use crate::array::ArrayParts;
20use crate::array::ArrayView;
21use crate::array::EmptyArrayData;
22use crate::array::OperationsVTable;
23use crate::array::VTable;
24use crate::array::ValidityVTable;
25use crate::array::with_empty_buffers;
26use crate::arrays::Dict;
27use crate::arrays::dict::TakeExecuteAdaptor;
28use crate::arrays::null::compute::rules::PARENT_RULES;
29use crate::buffer::BufferHandle;
30use crate::builders::ArrayBuilder;
31use crate::builders::NullBuilder;
32use crate::dtype::DType;
33use crate::optimizer::kernels::ArrayKernelsExt;
34use crate::scalar::Scalar;
35use crate::serde::ArrayChildren;
36use crate::validity::Validity;
37
38pub(crate) mod compute;
39
40/// A [`Null`]-encoded Vortex array.
41pub type NullArray = Array<Null>;
42
43pub(crate) fn initialize(session: &VortexSession) {
44    session
45        .kernels()
46        .register_execute_parent_kernel(Dict.id(), Null, TakeExecuteAdaptor(Null));
47}
48
49impl VTable for Null {
50    type TypedArrayData = EmptyArrayData;
51
52    type OperationsVTable = Self;
53    type ValidityVTable = Self;
54
55    fn id(&self) -> ArrayId {
56        static ID: CachedId = CachedId::new("vortex.null");
57        *ID
58    }
59
60    fn validate(
61        &self,
62        _data: &EmptyArrayData,
63        dtype: &DType,
64        _len: usize,
65        _slots: &[Option<ArrayRef>],
66    ) -> VortexResult<()> {
67        vortex_ensure_eq!(*dtype, DType::Null, "NullArray dtype must be DType::Null");
68        Ok(())
69    }
70
71    fn nbuffers(_array: ArrayView<'_, Self>) -> usize {
72        0
73    }
74
75    fn buffer(_array: ArrayView<'_, Self>, idx: usize) -> BufferHandle {
76        vortex_panic!("NullArray buffer index {idx} out of bounds")
77    }
78
79    fn buffer_name(_array: ArrayView<'_, Self>, _idx: usize) -> Option<String> {
80        None
81    }
82
83    fn with_buffers(
84        &self,
85        array: ArrayView<'_, Self>,
86        buffers: &[BufferHandle],
87    ) -> VortexResult<ArrayParts<Self>> {
88        with_empty_buffers(self, array, buffers)
89    }
90
91    fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String {
92        vortex_panic!("NullArray slot_name index {idx} out of bounds")
93    }
94
95    fn serialize(
96        _array: ArrayView<'_, Self>,
97        _session: &VortexSession,
98    ) -> VortexResult<Option<Vec<u8>>> {
99        Ok(Some(vec![]))
100    }
101
102    fn deserialize(
103        &self,
104        dtype: &DType,
105        len: usize,
106        metadata: &[u8],
107
108        _buffers: &[BufferHandle],
109        _children: &dyn ArrayChildren,
110        _session: &VortexSession,
111    ) -> VortexResult<ArrayParts<Self>> {
112        vortex_ensure!(
113            metadata.is_empty(),
114            "NullArray expects empty metadata, got {} bytes",
115            metadata.len()
116        );
117        Ok(ArrayParts::new(
118            self.clone(),
119            dtype.clone(),
120            len,
121            EmptyArrayData,
122            ArraySlots::new(),
123        ))
124    }
125
126    fn reduce_parent(
127        array: ArrayView<'_, Self>,
128        parent: &ArrayRef,
129        child_idx: usize,
130    ) -> VortexResult<Option<ArrayRef>> {
131        PARENT_RULES.evaluate(array, parent, child_idx)
132    }
133
134    fn execute(array: Array<Self>, _ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
135        Ok(ExecutionResult::done(array))
136    }
137
138    fn append_to_builder(
139        array: ArrayView<'_, Self>,
140        builder: &mut dyn ArrayBuilder,
141        _ctx: &mut ExecutionCtx,
142    ) -> VortexResult<()> {
143        let Some(builder) = builder.as_any_mut().downcast_mut::<NullBuilder>() else {
144            vortex_bail!("append_to_builder for Null requires a NullBuilder");
145        };
146        builder.append_nulls(array.len());
147        Ok(())
148    }
149}
150
151/// A array where all values are null.
152///
153/// This mirrors the Apache Arrow Null array encoding and provides an efficient representation
154/// for arrays containing only null values. No actual data is stored, only the length.
155///
156/// All operations on null arrays return null values or indicate invalid data.
157///
158/// # Examples
159///
160/// ```
161/// # fn main() -> vortex_error::VortexResult<()> {
162/// use vortex_array::arrays::NullArray;
163/// use vortex_array::{IntoArray, VortexSessionExecute, array_session};
164///
165/// // Create a null array with 5 elements
166/// let array = NullArray::new(5);
167///
168/// // Slice the array - still contains nulls
169/// let sliced = array.slice(1..3)?;
170/// assert_eq!(sliced.len(), 2);
171///
172/// // All elements are null
173/// let mut ctx = array_session().create_execution_ctx();
174/// let scalar = array.execute_scalar(0, &mut ctx).unwrap();
175/// assert!(scalar.is_null());
176/// # Ok(())
177/// # }
178/// ```
179#[derive(Clone, Debug)]
180pub struct Null;
181
182impl Array<Null> {
183    pub fn new(len: usize) -> Self {
184        unsafe {
185            Array::from_parts_unchecked(ArrayParts::new(
186                Null,
187                DType::Null,
188                len,
189                EmptyArrayData,
190                ArraySlots::new(),
191            ))
192        }
193    }
194}
195
196impl OperationsVTable<Null> for Null {
197    type ProbeState = ();
198
199    fn scalar_at(
200        _array: ArrayView<'_, Null>,
201        _index: usize,
202        _ctx: &mut ExecutionCtx,
203    ) -> VortexResult<Scalar> {
204        Ok(Scalar::null(DType::Null))
205    }
206}
207
208impl ValidityVTable<Null> for Null {
209    fn validity(_array: ArrayView<'_, Null>) -> VortexResult<Validity> {
210        Ok(Validity::AllInvalid)
211    }
212}