Skip to main content

arrow_array/array/
null_array.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! Contains the `NullArray` type.
6
7use crate::builder::NullBuilder;
8use crate::{Array, ArrayRef};
9use arrow_buffer::buffer::NullBuffer;
10use arrow_data::{ArrayData, ArrayDataBuilder};
11use arrow_schema::DataType;
12use std::any::Any;
13use std::sync::Arc;
14
15/// An array of [null values](https://arrow.apache.org/docs/format/Columnar.html#null-layout)
16///
17/// A `NullArray` is a simplified array where all values are null.
18///
19/// # Example: Create an array
20///
21/// ```
22/// use arrow_array::{Array, NullArray};
23///
24/// let array = NullArray::new(10);
25///
26/// assert!(array.is_nullable());
27/// assert_eq!(array.len(), 10);
28/// assert_eq!(array.null_count(), 0);
29/// assert_eq!(array.logical_null_count(), 10);
30/// assert_eq!(array.logical_nulls().unwrap().null_count(), 10);
31/// ```
32#[derive(Clone)]
33pub struct NullArray {
34    len: usize,
35}
36
37impl NullArray {
38    /// Create a new [`NullArray`] of the specified length
39    ///
40    /// *Note*: Use [`crate::array::new_null_array`] if you need an array of some
41    /// other [`DataType`].
42    ///
43    pub fn new(length: usize) -> Self {
44        Self { len: length }
45    }
46
47    /// Returns a zero-copy slice of this array with the indicated offset and length.
48    ///
49    /// # Panics
50    /// Panics if `offset + len > self.len()`
51    pub fn slice(&self, offset: usize, len: usize) -> Self {
52        assert!(
53            offset.saturating_add(len) <= self.len,
54            "the length + offset of the sliced BooleanBuffer cannot exceed the existing length"
55        );
56
57        Self { len }
58    }
59
60    /// Returns a new null array builder
61    ///
62    /// Note that the `capacity` parameter to this function is _deprecated_. It
63    /// now does nothing, and will be removed in a future version.
64    pub fn builder(_capacity: usize) -> NullBuilder {
65        NullBuilder::new()
66    }
67}
68
69/// SAFETY: Correctly implements the contract of Arrow Arrays
70unsafe impl Array for NullArray {
71    fn as_any(&self) -> &dyn Any {
72        self
73    }
74
75    fn to_data(&self) -> ArrayData {
76        self.clone().into()
77    }
78
79    fn into_data(self) -> ArrayData {
80        self.into()
81    }
82
83    fn data_type(&self) -> &DataType {
84        &DataType::Null
85    }
86
87    fn slice(&self, offset: usize, length: usize) -> ArrayRef {
88        Arc::new(self.slice(offset, length))
89    }
90
91    fn len(&self) -> usize {
92        self.len
93    }
94
95    fn is_empty(&self) -> bool {
96        self.len == 0
97    }
98
99    fn offset(&self) -> usize {
100        0
101    }
102
103    fn nulls(&self) -> Option<&NullBuffer> {
104        None
105    }
106
107    fn logical_nulls(&self) -> Option<NullBuffer> {
108        (self.len != 0).then(|| NullBuffer::new_null(self.len))
109    }
110
111    fn is_nullable(&self) -> bool {
112        !self.is_empty()
113    }
114
115    fn logical_null_count(&self) -> usize {
116        self.len
117    }
118
119    fn get_buffer_memory_size(&self) -> usize {
120        0
121    }
122
123    fn get_array_memory_size(&self) -> usize {
124        std::mem::size_of::<Self>()
125    }
126
127    #[cfg(feature = "pool")]
128    fn claim(&self, _pool: &dyn arrow_buffer::MemoryPool) {
129        // NullArray has no buffers to claim
130    }
131}
132
133impl From<ArrayData> for NullArray {
134    fn from(data: ArrayData) -> Self {
135        let (data_type, len, nulls, _offset, buffers, _child_data) = data.into_parts();
136
137        assert_eq!(
138            data_type,
139            DataType::Null,
140            "NullArray data type should be Null"
141        );
142        assert_eq!(buffers.len(), 0, "NullArray data should contain 0 buffers");
143        assert!(
144            nulls.is_none(),
145            "NullArray data should not contain a null buffer, as no buffers are required"
146        );
147        Self { len }
148    }
149}
150
151impl From<NullArray> for ArrayData {
152    fn from(array: NullArray) -> Self {
153        let builder = ArrayDataBuilder::new(DataType::Null).len(array.len);
154        unsafe { builder.build_unchecked() }
155    }
156}
157
158impl std::fmt::Debug for NullArray {
159    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
160        write!(f, "NullArray({})", self.len())
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167    use crate::{Int64Array, StructArray, make_array};
168    use arrow_data::transform::MutableArrayData;
169    use arrow_schema::Field;
170
171    #[test]
172    fn test_null_array() {
173        let null_arr = NullArray::new(32);
174
175        assert_eq!(null_arr.len(), 32);
176        assert_eq!(null_arr.null_count(), 0);
177        assert_eq!(null_arr.logical_null_count(), 32);
178        assert_eq!(null_arr.logical_nulls().unwrap().null_count(), 32);
179        assert!(null_arr.is_valid(0));
180        assert!(null_arr.is_nullable());
181    }
182
183    #[test]
184    fn test_null_array_slice() {
185        let array1 = NullArray::new(32);
186
187        let array2 = array1.slice(8, 16);
188        assert_eq!(array2.len(), 16);
189        assert_eq!(array2.null_count(), 0);
190        assert_eq!(array2.logical_null_count(), 16);
191        assert_eq!(array2.logical_nulls().unwrap().null_count(), 16);
192        assert!(array2.is_valid(0));
193        assert!(array2.is_nullable());
194    }
195
196    #[test]
197    fn test_debug_null_array() {
198        let array = NullArray::new(1024 * 1024);
199        assert_eq!(format!("{array:?}"), "NullArray(1048576)");
200    }
201
202    #[test]
203    fn test_null_array_with_parent_null_buffer() {
204        let null_array = NullArray::new(1);
205        let int_array = Int64Array::from(vec![42]);
206
207        let fields = vec![
208            Field::new("a", DataType::Int64, true),
209            Field::new("b", DataType::Null, true),
210        ];
211
212        let struct_array_data = ArrayData::builder(DataType::Struct(fields.into()))
213            .len(1)
214            .add_child_data(int_array.to_data())
215            .add_child_data(null_array.to_data())
216            .build()
217            .unwrap();
218
219        let mut mutable = MutableArrayData::new(vec![&struct_array_data], true, 1);
220
221        // Simulate a NULL value in the parent array, for instance, if array being queried by
222        // invalid index
223        mutable.try_extend_nulls(1).unwrap();
224        let data = mutable.freeze();
225
226        let struct_array = Arc::new(StructArray::from(data.clone()));
227        assert_eq!(&make_array(data), &(struct_array as ArrayRef));
228    }
229}