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