## 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
    }