vortex_array/arrays/null/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::hash::Hash;
5use std::ops::Range;
6
7use vortex_buffer::ByteBuffer;
8use vortex_dtype::DType;
9use vortex_error::VortexResult;
10use vortex_mask::Mask;
11use vortex_scalar::Scalar;
12use vortex_vector::null::NullVector;
13
14use crate::execution::{BatchKernelRef, BindCtx, kernel};
15use crate::serde::ArrayChildren;
16use crate::stats::{ArrayStats, StatsSetRef};
17use crate::vtable::{
18    ArrayVTable, CanonicalVTable, NotSupported, OperationsVTable, OperatorVTable, SerdeVTable,
19    VTable, ValidityVTable, VisitorVTable,
20};
21use crate::{
22    ArrayBufferVisitor, ArrayChildVisitor, ArrayRef, Canonical, EmptyMetadata, EncodingId,
23    EncodingRef, IntoArray, Precision, vtable,
24};
25
26mod compute;
27
28vtable!(Null);
29
30impl VTable for NullVTable {
31    type Array = NullArray;
32    type Encoding = NullEncoding;
33
34    type ArrayVTable = Self;
35    type CanonicalVTable = Self;
36    type OperationsVTable = Self;
37    type ValidityVTable = Self;
38    type VisitorVTable = Self;
39    type ComputeVTable = NotSupported;
40    type EncodeVTable = NotSupported;
41    type SerdeVTable = Self;
42    type OperatorVTable = Self;
43
44    fn id(_encoding: &Self::Encoding) -> EncodingId {
45        EncodingId::new_ref("vortex.null")
46    }
47
48    fn encoding(_array: &Self::Array) -> EncodingRef {
49        EncodingRef::new_ref(NullEncoding.as_ref())
50    }
51}
52
53/// A array where all values are null.
54///
55/// This mirrors the Apache Arrow Null array encoding and provides an efficient representation
56/// for arrays containing only null values. No actual data is stored, only the length.
57///
58/// All operations on null arrays return null values or indicate invalid data.
59///
60/// # Examples
61///
62/// ```
63/// use vortex_array::arrays::NullArray;
64/// use vortex_array::IntoArray;
65///
66/// // Create a null array with 5 elements
67/// let array = NullArray::new(5);
68///
69/// // Slice the array - still contains nulls
70/// let sliced = array.slice(1..3);
71/// assert_eq!(sliced.len(), 2);
72///
73/// // All elements are null
74/// let scalar = array.scalar_at(0);
75/// assert!(scalar.is_null());
76/// ```
77#[derive(Clone, Debug)]
78pub struct NullArray {
79    len: usize,
80    stats_set: ArrayStats,
81}
82
83#[derive(Clone, Debug)]
84pub struct NullEncoding;
85
86impl NullArray {
87    pub fn new(len: usize) -> Self {
88        Self {
89            len,
90            stats_set: Default::default(),
91        }
92    }
93}
94
95impl ArrayVTable<NullVTable> for NullVTable {
96    fn len(array: &NullArray) -> usize {
97        array.len
98    }
99
100    fn dtype(_array: &NullArray) -> &DType {
101        &DType::Null
102    }
103
104    fn stats(array: &NullArray) -> StatsSetRef<'_> {
105        array.stats_set.to_ref(array.as_ref())
106    }
107
108    fn array_hash<H: std::hash::Hasher>(array: &NullArray, state: &mut H, _precision: Precision) {
109        array.len.hash(state);
110    }
111
112    fn array_eq(array: &NullArray, other: &NullArray, _precision: Precision) -> bool {
113        array.len == other.len
114    }
115}
116
117impl SerdeVTable<NullVTable> for NullVTable {
118    type Metadata = EmptyMetadata;
119
120    fn metadata(_array: &NullArray) -> VortexResult<Option<Self::Metadata>> {
121        Ok(Some(EmptyMetadata))
122    }
123
124    fn build(
125        _encoding: &NullEncoding,
126        _dtype: &DType,
127        len: usize,
128        _metadata: &Self::Metadata,
129        _buffers: &[ByteBuffer],
130        _children: &dyn ArrayChildren,
131    ) -> VortexResult<NullArray> {
132        Ok(NullArray::new(len))
133    }
134}
135
136impl VisitorVTable<NullVTable> for NullVTable {
137    fn visit_buffers(_array: &NullArray, _visitor: &mut dyn ArrayBufferVisitor) {}
138
139    fn visit_children(_array: &NullArray, _visitor: &mut dyn ArrayChildVisitor) {}
140}
141
142impl CanonicalVTable<NullVTable> for NullVTable {
143    fn canonicalize(array: &NullArray) -> Canonical {
144        Canonical::Null(array.clone())
145    }
146}
147
148impl OperationsVTable<NullVTable> for NullVTable {
149    fn slice(_array: &NullArray, range: Range<usize>) -> ArrayRef {
150        NullArray::new(range.len()).into_array()
151    }
152
153    fn scalar_at(_array: &NullArray, _index: usize) -> Scalar {
154        Scalar::null(DType::Null)
155    }
156}
157
158impl ValidityVTable<NullVTable> for NullVTable {
159    fn is_valid(_array: &NullArray, _index: usize) -> bool {
160        false
161    }
162
163    fn all_valid(array: &NullArray) -> bool {
164        array.is_empty()
165    }
166
167    fn all_invalid(array: &NullArray) -> bool {
168        !array.is_empty()
169    }
170
171    fn validity_mask(array: &NullArray) -> Mask {
172        Mask::AllFalse(array.len)
173    }
174}
175
176impl OperatorVTable<NullVTable> for NullVTable {
177    fn bind(
178        array: &NullArray,
179        _selection: Option<&ArrayRef>,
180        _ctx: &mut dyn BindCtx,
181    ) -> VortexResult<BatchKernelRef> {
182        let len = array.len();
183        Ok(kernel(move || Ok(NullVector::new(len).into())))
184    }
185}