polars_arrow/array/
null.rs

1use std::any::Any;
2
3use polars_error::{polars_bail, PolarsResult};
4
5use super::Splitable;
6use crate::array::{Array, FromFfi, MutableArray, ToFfi};
7use crate::bitmap::{Bitmap, MutableBitmap};
8use crate::datatypes::{ArrowDataType, PhysicalType};
9use crate::ffi;
10
11/// The concrete [`Array`] of [`ArrowDataType::Null`].
12#[derive(Clone)]
13pub struct NullArray {
14    dtype: ArrowDataType,
15
16    /// Validity mask. This is always all-zeroes.
17    validity: Bitmap,
18
19    length: usize,
20}
21
22impl NullArray {
23    /// Returns a new [`NullArray`].
24    /// # Errors
25    /// This function errors iff:
26    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
27    pub fn try_new(dtype: ArrowDataType, length: usize) -> PolarsResult<Self> {
28        if dtype.to_physical_type() != PhysicalType::Null {
29            polars_bail!(ComputeError: "NullArray can only be initialized with a DataType whose physical type is Null");
30        }
31
32        let validity = Bitmap::new_zeroed(length);
33
34        Ok(Self {
35            dtype,
36            validity,
37            length,
38        })
39    }
40
41    /// Returns a new [`NullArray`].
42    /// # Panics
43    /// This function errors iff:
44    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
45    pub fn new(dtype: ArrowDataType, length: usize) -> Self {
46        Self::try_new(dtype, length).unwrap()
47    }
48
49    /// Returns a new empty [`NullArray`].
50    pub fn new_empty(dtype: ArrowDataType) -> Self {
51        Self::new(dtype, 0)
52    }
53
54    /// Returns a new [`NullArray`].
55    pub fn new_null(dtype: ArrowDataType, length: usize) -> Self {
56        Self::new(dtype, length)
57    }
58
59    impl_sliced!();
60    impl_into_array!();
61}
62
63impl NullArray {
64    /// Returns a slice of the [`NullArray`].
65    /// # Panic
66    /// This function panics iff `offset + length > self.len()`.
67    pub fn slice(&mut self, offset: usize, length: usize) {
68        assert!(
69            offset + length <= self.len(),
70            "the offset of the new array cannot exceed the arrays' length"
71        );
72        unsafe { self.slice_unchecked(offset, length) };
73    }
74
75    /// Returns a slice of the [`NullArray`].
76    ///
77    /// # Safety
78    /// The caller must ensure that `offset + length < self.len()`.
79    pub unsafe fn slice_unchecked(&mut self, offset: usize, length: usize) {
80        self.length = length;
81        self.validity.slice_unchecked(offset, length);
82    }
83
84    #[inline]
85    fn len(&self) -> usize {
86        self.length
87    }
88}
89
90impl Array for NullArray {
91    impl_common_array!();
92
93    fn validity(&self) -> Option<&Bitmap> {
94        Some(&self.validity)
95    }
96
97    fn with_validity(&self, _: Option<Bitmap>) -> Box<dyn Array> {
98        // Nulls with invalid nulls are also nulls.
99        self.clone().boxed()
100    }
101}
102
103#[derive(Debug)]
104/// A distinct type to disambiguate
105/// clashing methods
106pub struct MutableNullArray {
107    inner: NullArray,
108}
109
110impl MutableNullArray {
111    /// Returns a new [`MutableNullArray`].
112    /// # Panics
113    /// This function errors iff:
114    /// * The `dtype`'s [`crate::datatypes::PhysicalType`] is not equal to [`crate::datatypes::PhysicalType::Null`].
115    pub fn new(dtype: ArrowDataType, length: usize) -> Self {
116        let inner = NullArray::try_new(dtype, length).unwrap();
117        Self { inner }
118    }
119}
120
121impl From<MutableNullArray> for NullArray {
122    fn from(value: MutableNullArray) -> Self {
123        value.inner
124    }
125}
126
127impl MutableArray for MutableNullArray {
128    fn dtype(&self) -> &ArrowDataType {
129        &ArrowDataType::Null
130    }
131
132    fn len(&self) -> usize {
133        self.inner.length
134    }
135
136    fn validity(&self) -> Option<&MutableBitmap> {
137        None
138    }
139
140    fn as_box(&mut self) -> Box<dyn Array> {
141        self.inner.clone().boxed()
142    }
143
144    fn as_any(&self) -> &dyn Any {
145        self
146    }
147
148    fn as_mut_any(&mut self) -> &mut dyn Any {
149        self
150    }
151
152    fn push_null(&mut self) {
153        self.inner.length += 1;
154    }
155
156    fn reserve(&mut self, _additional: usize) {
157        // no-op
158    }
159
160    fn shrink_to_fit(&mut self) {
161        // no-op
162    }
163}
164
165impl std::fmt::Debug for NullArray {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        write!(f, "NullArray({})", self.len())
168    }
169}
170
171unsafe impl ToFfi for NullArray {
172    fn buffers(&self) -> Vec<Option<*const u8>> {
173        // `None` is technically not required by the specification, but older C++ implementations require it, so leaving
174        // it here for backward compatibility
175        vec![None]
176    }
177
178    fn offset(&self) -> Option<usize> {
179        Some(0)
180    }
181
182    fn to_ffi_aligned(&self) -> Self {
183        self.clone()
184    }
185}
186
187impl Splitable for NullArray {
188    fn check_bound(&self, offset: usize) -> bool {
189        offset <= self.len()
190    }
191
192    unsafe fn _split_at_unchecked(&self, offset: usize) -> (Self, Self) {
193        let (lhs, rhs) = self.validity.split_at(offset);
194
195        (
196            Self {
197                dtype: self.dtype.clone(),
198                validity: lhs,
199                length: offset,
200            },
201            Self {
202                dtype: self.dtype.clone(),
203                validity: rhs,
204                length: self.len() - offset,
205            },
206        )
207    }
208}
209
210impl<A: ffi::ArrowArrayRef> FromFfi<A> for NullArray {
211    unsafe fn try_from_ffi(array: A) -> PolarsResult<Self> {
212        let dtype = array.dtype().clone();
213        Self::try_new(dtype, array.array().len())
214    }
215}