Coverage Report

Created: 2025-08-26 07:03

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