polars_arrow/array/
null.rs

1use std::any::Any;
2
3use polars_error::{PolarsResult, polars_bail};
4use polars_utils::IdxSize;
5
6use super::Splitable;
7use crate::array::builder::{ShareStrategy, StaticArrayBuilder};
8use crate::array::{Array, FromFfi, MutableArray, ToFfi};
9use crate::bitmap::{Bitmap, MutableBitmap};
10use crate::datatypes::{ArrowDataType, PhysicalType};
11use crate::ffi;
12
13/// The concrete [`Array`] of [`ArrowDataType::Null`].
14#[derive(Clone)]
15pub struct NullArray {
16    dtype: ArrowDataType,
17
18    /// Validity mask. This is always all-zeroes.
19    validity: Bitmap,
20
21    length: usize,
22}
23
24impl NullArray {
25    /// Returns a new [`NullArray`].
26    /// # Errors
27    /// This function errors iff:
28    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
29    pub fn try_new(dtype: ArrowDataType, length: usize) -> PolarsResult<Self> {
30        if dtype.to_physical_type() != PhysicalType::Null {
31            polars_bail!(ComputeError: "NullArray can only be initialized with a DataType whose physical type is Null");
32        }
33
34        let validity = Bitmap::new_zeroed(length);
35
36        Ok(Self {
37            dtype,
38            validity,
39            length,
40        })
41    }
42
43    /// Returns a new [`NullArray`].
44    /// # Panics
45    /// This function errors iff:
46    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
47    pub fn new(dtype: ArrowDataType, length: usize) -> Self {
48        Self::try_new(dtype, length).unwrap()
49    }
50
51    /// Returns a new empty [`NullArray`].
52    pub fn new_empty(dtype: ArrowDataType) -> Self {
53        Self::new(dtype, 0)
54    }
55
56    /// Returns a new [`NullArray`].
57    pub fn new_null(dtype: ArrowDataType, length: usize) -> Self {
58        Self::new(dtype, length)
59    }
60
61    impl_sliced!();
62    impl_into_array!();
63}
64
65impl NullArray {
66    /// Returns a slice of the [`NullArray`].
67    /// # Panic
68    /// This function panics iff `offset + length > self.len()`.
69    pub fn slice(&mut self, offset: usize, length: usize) {
70        assert!(
71            offset + length <= self.len(),
72            "the offset of the new array cannot exceed the arrays' length"
73        );
74        unsafe { self.slice_unchecked(offset, length) };
75    }
76
77    /// Returns a slice of the [`NullArray`].
78    ///
79    /// # Safety
80    /// The caller must ensure that `offset + length < self.len()`.
81    pub unsafe fn slice_unchecked(&mut self, offset: usize, length: usize) {
82        self.length = length;
83        self.validity.slice_unchecked(offset, length);
84    }
85
86    #[inline]
87    pub fn len(&self) -> usize {
88        self.length
89    }
90}
91
92impl Array for NullArray {
93    impl_common_array!();
94
95    fn validity(&self) -> Option<&Bitmap> {
96        Some(&self.validity)
97    }
98
99    fn with_validity(&self, _: Option<Bitmap>) -> Box<dyn Array> {
100        // Nulls with invalid nulls are also nulls.
101        self.clone().boxed()
102    }
103}
104
105#[derive(Debug)]
106/// A distinct type to disambiguate
107/// clashing methods
108pub struct MutableNullArray {
109    inner: NullArray,
110}
111
112impl MutableNullArray {
113    /// Returns a new [`MutableNullArray`].
114    /// # Panics
115    /// This function errors iff:
116    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
117    pub fn new(dtype: ArrowDataType, length: usize) -> Self {
118        let inner = NullArray::try_new(dtype, length).unwrap();
119        Self { inner }
120    }
121}
122
123impl From<MutableNullArray> for NullArray {
124    fn from(value: MutableNullArray) -> Self {
125        value.inner
126    }
127}
128
129impl MutableArray for MutableNullArray {
130    fn dtype(&self) -> &ArrowDataType {
131        &ArrowDataType::Null
132    }
133
134    fn len(&self) -> usize {
135        self.inner.length
136    }
137
138    fn validity(&self) -> Option<&MutableBitmap> {
139        None
140    }
141
142    fn as_box(&mut self) -> Box<dyn Array> {
143        self.inner.clone().boxed()
144    }
145
146    fn as_any(&self) -> &dyn Any {
147        self
148    }
149
150    fn as_mut_any(&mut self) -> &mut dyn Any {
151        self
152    }
153
154    fn push_null(&mut self) {
155        self.inner.length += 1;
156    }
157
158    fn reserve(&mut self, _additional: usize) {
159        // no-op
160    }
161
162    fn shrink_to_fit(&mut self) {
163        // no-op
164    }
165}
166
167impl std::fmt::Debug for NullArray {
168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169        write!(f, "NullArray({})", self.len())
170    }
171}
172
173unsafe impl ToFfi for NullArray {
174    fn buffers(&self) -> Vec<Option<*const u8>> {
175        // `None` is technically not required by the specification, but older C++ implementations require it, so leaving
176        // it here for backward compatibility
177        vec![None]
178    }
179
180    fn offset(&self) -> Option<usize> {
181        Some(0)
182    }
183
184    fn to_ffi_aligned(&self) -> Self {
185        self.clone()
186    }
187}
188
189impl Splitable for NullArray {
190    fn check_bound(&self, offset: usize) -> bool {
191        offset <= self.len()
192    }
193
194    unsafe fn _split_at_unchecked(&self, offset: usize) -> (Self, Self) {
195        let (lhs, rhs) = self.validity.split_at(offset);
196
197        (
198            Self {
199                dtype: self.dtype.clone(),
200                validity: lhs,
201                length: offset,
202            },
203            Self {
204                dtype: self.dtype.clone(),
205                validity: rhs,
206                length: self.len() - offset,
207            },
208        )
209    }
210}
211
212impl<A: ffi::ArrowArrayRef> FromFfi<A> for NullArray {
213    unsafe fn try_from_ffi(array: A) -> PolarsResult<Self> {
214        let dtype = array.dtype().clone();
215        Self::try_new(dtype, array.array().len())
216    }
217}
218
219pub struct NullArrayBuilder {
220    dtype: ArrowDataType,
221    length: usize,
222}
223
224impl NullArrayBuilder {
225    pub fn new(dtype: ArrowDataType) -> Self {
226        Self { dtype, length: 0 }
227    }
228}
229
230impl StaticArrayBuilder for NullArrayBuilder {
231    type Array = NullArray;
232
233    fn dtype(&self) -> &ArrowDataType {
234        &self.dtype
235    }
236
237    fn reserve(&mut self, _additional: usize) {}
238
239    fn freeze(self) -> NullArray {
240        NullArray::new(self.dtype, self.length)
241    }
242
243    fn freeze_reset(&mut self) -> Self::Array {
244        let out = NullArray::new(self.dtype.clone(), self.length);
245        self.length = 0;
246        out
247    }
248
249    fn len(&self) -> usize {
250        self.length
251    }
252
253    fn extend_nulls(&mut self, length: usize) {
254        self.length += length;
255    }
256
257    fn subslice_extend(
258        &mut self,
259        _other: &NullArray,
260        _start: usize,
261        length: usize,
262        _share: ShareStrategy,
263    ) {
264        self.length += length;
265    }
266
267    fn subslice_extend_repeated(
268        &mut self,
269        _other: &NullArray,
270        _start: usize,
271        length: usize,
272        repeats: usize,
273        _share: ShareStrategy,
274    ) {
275        self.length += length * repeats;
276    }
277
278    fn subslice_extend_each_repeated(
279        &mut self,
280        _other: &NullArray,
281        _start: usize,
282        length: usize,
283        repeats: usize,
284        _share: ShareStrategy,
285    ) {
286        self.length += length * repeats;
287    }
288
289    unsafe fn gather_extend(
290        &mut self,
291        _other: &NullArray,
292        idxs: &[IdxSize],
293        _share: ShareStrategy,
294    ) {
295        self.length += idxs.len();
296    }
297
298    fn opt_gather_extend(&mut self, _other: &NullArray, idxs: &[IdxSize], _share: ShareStrategy) {
299        self.length += idxs.len();
300    }
301}