## 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/fixed_size_list_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
    use crate::array::print_long_array;
    19
    use crate::builder::{FixedSizeListBuilder, PrimitiveBuilder};
    20
    use crate::iterator::FixedSizeListIter;
    21
    use crate::{make_array, Array, ArrayAccessor, ArrayRef, ArrowPrimitiveType};
    22
    use arrow_buffer::buffer::NullBuffer;
    23
    use arrow_buffer::ArrowNativeType;
    24
    use arrow_data::{ArrayData, ArrayDataBuilder};
    25
    use arrow_schema::{ArrowError, DataType, FieldRef};
    26
    use std::any::Any;
    27
    use std::sync::Arc;
    28
    29
    /// An array of [fixed length lists], similar to JSON arrays
    30
    /// (e.g. `["A", "B"]`).
    31
    ///
    32
    /// Lists are represented using a `values` child
    33
    /// array where each list has a fixed size of `value_length`.
    34
    ///
    35
    /// Use [`FixedSizeListBuilder`] to construct a [`FixedSizeListArray`].
    36
    ///
    37
    /// # Representation
    38
    ///
    39
    /// A [`FixedSizeListArray`] can represent a list of values of any other
    40
    /// supported Arrow type. Each element of the `FixedSizeListArray` itself is
    41
    /// a list which may contain NULL and non-null values,
    42
    /// or may itself be NULL.
    43
    ///
    44
    /// For example, this `FixedSizeListArray` stores lists of strings:
    45
    ///
    46
    /// ```text
    47
    /// ┌─────────────┐
    48
    /// │    [A,B]    │
    49
    /// ├─────────────┤
    50
    /// │    NULL     │
    51
    /// ├─────────────┤
    52
    /// │   [C,NULL]  │
    53
    /// └─────────────┘
    54
    /// ```
    55
    ///
    56
    /// The `values` of this `FixedSizeListArray`s are stored in a child
    57
    /// [`StringArray`] where logical null values take up `values_length` slots in the array
    58
    /// as shown in the following diagram. The logical values
    59
    /// are shown on the left, and the actual `FixedSizeListArray` encoding on the right
    60
    ///
    61
    /// ```text
    62
    ///                                 ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
    63
    ///                                                         ┌ ─ ─ ─ ─ ─ ─ ─ ─┐
    64
    ///  ┌─────────────┐                │     ┌───┐               ┌───┐ ┌──────┐      │
    65
    ///  │   [A,B]     │                      │ 1 │             │ │ 1 │ │  A   │ │ 0
    66
    ///  ├─────────────┤                │     ├───┤               ├───┤ ├──────┤      │
    67
    ///  │    NULL     │                      │ 0 │             │ │ 1 │ │  B   │ │ 1
    68
    ///  ├─────────────┤                │     ├───┤               ├───┤ ├──────┤      │
    69
    ///  │  [C,NULL]   │                      │ 1 │             │ │ 0 │ │ ???? │ │ 2
    70
    ///  └─────────────┘                │     └───┘               ├───┤ ├──────┤      │
    71
    ///                                                         | │ 0 │ │ ???? │ │ 3
    72
    ///  Logical Values                 │   Validity              ├───┤ ├──────┤      │
    73
    ///                                     (nulls)             │ │ 1 │ │  C   │ │ 4
    74
    ///                                 │                         ├───┤ ├──────┤      │
    75
    ///                                                         │ │ 0 │ │ ???? │ │ 5
    76
    ///                                 │                         └───┘ └──────┘      │
    77
    ///                                                         │     Values     │
    78
    ///                                 │   FixedSizeListArray        (Array)         │
    79
    ///                                                         └ ─ ─ ─ ─ ─ ─ ─ ─┘
    80
    ///                                 └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
    81
    /// ```
    82
    ///
    83
    /// # Example
    84
    ///
    85
    /// ```
    86
    /// # use std::sync::Arc;
    87
    /// # use arrow_array::{Array, FixedSizeListArray, Int32Array};
    88
    /// # use arrow_data::ArrayData;
    89
    /// # use arrow_schema::{DataType, Field};
    90
    /// # use arrow_buffer::Buffer;
    91
    /// // Construct a value array
    92
    /// let value_data = ArrayData::builder(DataType::Int32)
    93
    ///     .len(9)
    94
    ///     .add_buffer(Buffer::from_slice_ref(&[0, 1, 2, 3, 4, 5, 6, 7, 8]))
    95
    ///     .build()
    96
    ///     .unwrap();
    97
    /// let list_data_type = DataType::FixedSizeList(
    98
    ///     Arc::new(Field::new_list_field(DataType::Int32, false)),
    99
    ///     3,
    100
    /// );
    101
    /// let list_data = ArrayData::builder(list_data_type.clone())
    102
    ///     .len(3)
    103
    ///     .add_child_data(value_data.clone())
    104
    ///     .build()
    105
    ///     .unwrap();
    106
    /// let list_array = FixedSizeListArray::from(list_data);
    107
    /// let list0 = list_array.value(0);
    108
    /// let list1 = list_array.value(1);
    109
    /// let list2 = list_array.value(2);
    110
    ///
    111
    /// assert_eq!( &[0, 1, 2], list0.as_any().downcast_ref::<Int32Array>().unwrap().values());
    112
    /// assert_eq!( &[3, 4, 5], list1.as_any().downcast_ref::<Int32Array>().unwrap().values());
    113
    /// assert_eq!( &[6, 7, 8], list2.as_any().downcast_ref::<Int32Array>().unwrap().values());
    114
    /// ```
    115
    ///
    116
    /// [`StringArray`]: crate::array::StringArray
    117
    /// [fixed size arrays](https://arrow.apache.org/docs/format/Columnar.html#fixed-size-list-layout)
    118
    #[derive(Clone)]
    119
    pub struct FixedSizeListArray {
    120
        data_type: DataType, // Must be DataType::FixedSizeList(value_length)
    121
        values: ArrayRef,
    122
        nulls: Option<NullBuffer>,
    123
        value_length: i32,
    124
        len: usize,
    125
    }
    126
    127
    impl FixedSizeListArray {
    128
        /// Create a new [`FixedSizeListArray`] with `size` element size, panicking on failure
    129
        ///
    130
        /// # Panics
    131
        ///
    132
        /// Panics if [`Self::try_new`] returns an error
    133
    0
        pub fn new(field: FieldRef, size: i32, values: ArrayRef, nulls: Option<NullBuffer>) -> Self {
    134
    0
            Self::try_new(field, size, values, nulls).unwrap()
    135
    0
        }
    136
    137
        /// Create a new [`FixedSizeListArray`] from the provided parts, returning an error on failure
    138
        ///
    139
        /// # Errors
    140
        ///
    141
        /// * `size < 0`
    142
        /// * `values.len() / size != nulls.len()`
    143
        /// * `values.data_type() != field.data_type()`
    144
        /// * `!field.is_nullable() && !nulls.expand(size).contains(values.logical_nulls())`
    145
    0
        pub fn try_new(
    146
    0
            field: FieldRef,
    147
    0
            size: i32,
    148
    0
            values: ArrayRef,
    149
    0
            nulls: Option<NullBuffer>,
    150
    0
        ) -> Result<Self, ArrowError> {
    151
    0
            let s = size.to_usize().ok_or_else(|| {
    152
    0
                ArrowError::InvalidArgumentError(format!("Size cannot be negative, got {size}"))
    153
    0
            })?;
    154
    155
    0
            let len = match s {
    156
    0
                0 => nulls.as_ref().map(|x| x.len()).unwrap_or_default(),
    157
                _ => {
    158
    0
                    let len = values.len() / s.max(1);
    159
    0
                    if let Some(n) = nulls.as_ref() {
    160
    0
                        if n.len() != len {
    161
    0
                            return Err(ArrowError::InvalidArgumentError(format!(
    162
    0
                                "Incorrect length of null buffer for FixedSizeListArray, expected {} got {}",
    163
    0
                                len,
    164
    0
                                n.len(),
    165
    0
                            )));
    166
    0
                        }
    167
    0
                    }
    168
    0
                    len
    169
                }
    170
            };
    171
    172
    0
            if field.data_type() != values.data_type() {
    173
    0
                return Err(ArrowError::InvalidArgumentError(format!(
    174
    0
                    "FixedSizeListArray expected data type {} got {} for {:?}",
    175
    0
                    field.data_type(),
    176
    0
                    values.data_type(),
    177
    0
                    field.name()
    178
    0
                )));
    179
    0
            }
    180
    181
    0
            if let Some(a) = values.logical_nulls() {
    182
    0
                let nulls_valid = field.is_nullable()
    183
    0
                    || nulls
    184
    0
                        .as_ref()
    185
    0
                        .map(|n| n.expand(size as _).contains(&a))
    186
    0
                        .unwrap_or_default()
    187
    0
                    || (nulls.is_none() && a.null_count() == 0);
    188
    189
    0
                if !nulls_valid {
    190
    0
                    return Err(ArrowError::InvalidArgumentError(format!(
    191
    0
                        "Found unmasked nulls for non-nullable FixedSizeListArray field {:?}",
    192
    0
                        field.name()
    193
    0
                    )));
    194
    0
                }
    195
    0
            }
    196
    197
    0
            let data_type = DataType::FixedSizeList(field, size);
    198
    0
            Ok(Self {
    199
    0
                data_type,
    200
    0
                values,
    201
    0
                value_length: size,
    202
    0
                nulls,
    203
    0
                len,
    204
    0
            })
    205
    0
        }
    206
    207
        /// Create a new [`FixedSizeListArray`] of length `len` where all values are null
    208
        ///
    209
        /// # Panics
    210
        ///
    211
        /// Panics if
    212
        ///
    213
        /// * `size < 0`
    214
        /// * `size * len` would overflow `usize`
    215
    0
        pub fn new_null(field: FieldRef, size: i32, len: usize) -> Self {
    216
    0
            let capacity = size.to_usize().unwrap().checked_mul(len).unwrap();
    217
    0
            Self {
    218
    0
                values: make_array(ArrayData::new_null(field.data_type(), capacity)),
    219
    0
                data_type: DataType::FixedSizeList(field, size),
    220
    0
                nulls: Some(NullBuffer::new_null(len)),
    221
    0
                value_length: size,
    222
    0
                len,
    223
    0
            }
    224
    0
        }
    225
    226
        /// Deconstruct this array into its constituent parts
    227
    0
        pub fn into_parts(self) -> (FieldRef, i32, ArrayRef, Option<NullBuffer>) {
    228
    0
            let f = match self.data_type {
    229
    0
                DataType::FixedSizeList(f, _) => f,
    230
    0
                _ => unreachable!(),
    231
            };
    232
    0
            (f, self.value_length, self.values, self.nulls)
    233
    0
        }
    234
    235
        /// Returns a reference to the values of this list.
    236
    0
        pub fn values(&self) -> &ArrayRef {
    237
    0
            &self.values
    238
    0
        }
    239
    240
        /// Returns a clone of the value type of this list.
    241
    0
        pub fn value_type(&self) -> DataType {
    242
    0
            self.values.data_type().clone()
    243
    0
        }
    244
    245
        /// Returns ith value of this list array.
    246
        ///
    247
        /// Note: This method does not check for nulls and the value is arbitrary
    248
        /// (but still well-defined) if [`is_null`](Self::is_null) returns true for the index.
    249
        ///
    250
        /// # Panics
    251
        /// Panics if index `i` is out of bounds
    252
    0
        pub fn value(&self, i: usize) -> ArrayRef {
    253
    0
            self.values
    254
    0
                .slice(self.value_offset_at(i), self.value_length() as usize)
    255
    0
        }
    256
    257
        /// Returns the offset for value at index `i`.
    258
        ///
    259
        /// Note this doesn't do any bound checking, for performance reason.
    260
        #[inline]
    261
    0
        pub fn value_offset(&self, i: usize) -> i32 {
    262
    0
            self.value_offset_at(i) as i32
    263
    0
        }
    264
    265
        /// Returns the length for an element.
    266
        ///
    267
        /// All elements have the same length as the array is a fixed size.
    268
        #[inline]
    269
    0
        pub const fn value_length(&self) -> i32 {
    270
    0
            self.value_length
    271
    0
        }
    272
    273
        #[inline]
    274
    0
        const fn value_offset_at(&self, i: usize) -> usize {
    275
    0
            i * self.value_length as usize
    276
    0
        }
    277
    278
        /// Returns a zero-copy slice of this array with the indicated offset and length.
    279
    0
        pub fn slice(&self, offset: usize, len: usize) -> Self {
    280
    0
            assert!(
    281
    0
                offset.saturating_add(len) <= self.len,
    282
    0
                "the length + offset of the sliced FixedSizeListArray cannot exceed the existing length"
    283
            );
    284
    0
            let size = self.value_length as usize;
    285
    286
            Self {
    287
    0
                data_type: self.data_type.clone(),
    288
    0
                values: self.values.slice(offset * size, len * size),
    289
    0
                nulls: self.nulls.as_ref().map(|n| n.slice(offset, len)),
    290
    0
                value_length: self.value_length,
    291
    0
                len,
    292
            }
    293
    0
        }
    294
    295
        /// Creates a [`FixedSizeListArray`] from an iterator of primitive values
    296
        /// # Example
    297
        /// ```
    298
        /// # use arrow_array::FixedSizeListArray;
    299
        /// # use arrow_array::types::Int32Type;
    300
        ///
    301
        /// let data = vec![
    302
        ///    Some(vec![Some(0), Some(1), Some(2)]),
    303
        ///    None,
    304
        ///    Some(vec![Some(3), None, Some(5)]),
    305
        ///    Some(vec![Some(6), Some(7), Some(45)]),
    306
        /// ];
    307
        /// let list_array = FixedSizeListArray::from_iter_primitive::<Int32Type, _, _>(data, 3);
    308
        /// println!("{:?}", list_array);
    309
        /// ```
    310
        pub fn from_iter_primitive<T, P, I>(iter: I, length: i32) -> Self
    311
        where
    312
            T: ArrowPrimitiveType,
    313
            P: IntoIterator<Item = Option<<T as ArrowPrimitiveType>::Native>>,
    314
            I: IntoIterator<Item = Option<P>>,
    315
        {
    316
            let l = length as usize;
    317
            let iter = iter.into_iter();
    318
            let size_hint = iter.size_hint().0;
    319
            let mut builder = FixedSizeListBuilder::with_capacity(
    320
                PrimitiveBuilder::<T>::with_capacity(size_hint * l),
    321
                length,
    322
                size_hint,
    323
            );
    324
    325
            for i in iter {
    326
                match i {
    327
                    Some(p) => {
    328
                        for t in p {
    329
                            builder.values().append_option(t);
    330
                        }
    331
                        builder.append(true);
    332
                    }
    333
                    None => {
    334
                        builder.values().append_nulls(l);
    335
                        builder.append(false)
    336
                    }
    337
                }
    338
            }
    339
            builder.finish()
    340
        }
    341
    342
        /// constructs a new iterator
    343
    0
        pub fn iter(&self) -> FixedSizeListIter<'_> {
    344
    0
            FixedSizeListIter::new(self)
    345
    0
        }
    346
    }
    347
    348
    impl From<ArrayData> for FixedSizeListArray {
    349
    0
        fn from(data: ArrayData) -> Self {
    350
    0
            let value_length = match data.data_type() {
    351
    0
                DataType::FixedSizeList(_, len) => *len,
    352
    0
                data_type => {
    353
    0
                    panic!("FixedSizeListArray data should contain a FixedSizeList data type, got {data_type:?}")
    354
                }
    355
            };
    356
    357
    0
            let size = value_length as usize;
    358
    0
            let values =
    359
    0
                make_array(data.child_data()[0].slice(data.offset() * size, data.len() * size));
    360
    0
            Self {
    361
    0
                data_type: data.data_type().clone(),
    362
    0
                values,
    363
    0
                nulls: data.nulls().cloned(),
    364
    0
                value_length,
    365
    0
                len: data.len(),
    366
    0
            }
    367
    0
        }
    368
    }
    369
    370
    impl From<FixedSizeListArray> for ArrayData {
    371
    0
        fn from(array: FixedSizeListArray) -> Self {
    372
    0
            let builder = ArrayDataBuilder::new(array.data_type)
    373
    0
                .len(array.len)
    374
    0
                .nulls(array.nulls)
    375
    0
                .child_data(vec![array.values.to_data()]);
    376
    377
    0
            unsafe { builder.build_unchecked() }
    378
    0
        }
    379
    }
    380
    381
    impl Array for FixedSizeListArray {
    382
    0
        fn as_any(&self) -> &dyn Any {
    383
    0
            self
    384
    0
        }
    385
    386
    0
        fn to_data(&self) -> ArrayData {
    387
    0
            self.clone().into()
    388
    0
        }
    389
    390
    0
        fn into_data(self) -> ArrayData {
    391
    0
            self.into()
    392
    0
        }
    393
    394
    0
        fn data_type(&self) -> &DataType {
    395
    0
            &self.data_type
    396
    0
        }
    397
    398
    0
        fn slice(&self, offset: usize, length: usize) -> ArrayRef {
    399
    0
            Arc::new(self.slice(offset, length))
    400
    0
        }
    401
    402
    0
        fn len(&self) -> usize {
    403
    0
            self.len
    404
    0
        }
    405
    406
    0
        fn is_empty(&self) -> bool {
    407
    0
            self.len == 0
    408
    0
        }
    409
    410
    0
        fn shrink_to_fit(&mut self) {
    411
    0
            self.values.shrink_to_fit();
    412
    0
            if let Some(nulls) = &mut self.nulls {
    413
    0
                nulls.shrink_to_fit();
    414
    0
            }
    415
    0
        }
    416
    417
    0
        fn offset(&self) -> usize {
    418
    0
            0
    419
    0
        }
    420
    421
    0
        fn nulls(&self) -> Option<&NullBuffer> {
    422
    0
            self.nulls.as_ref()
    423
    0
        }
    424
    425
    0
        fn logical_null_count(&self) -> usize {
    426
            // More efficient that the default implementation
    427
    0
            self.null_count()
    428
    0
        }
    429
    430
    0
        fn get_buffer_memory_size(&self) -> usize {
    431
    0
            let mut size = self.values.get_buffer_memory_size();
    432
    0
            if let Some(n) = self.nulls.as_ref() {
    433
    0
                size += n.buffer().capacity();
    434
    0
            }
    435
    0
            size
    436
    0
        }
    437
    438
    0
        fn get_array_memory_size(&self) -> usize {
    439
    0
            let mut size = std::mem::size_of::<Self>() + self.values.get_array_memory_size();
    440
    0
            if let Some(n) = self.nulls.as_ref() {
    441
    0
                size += n.buffer().capacity();
    442
    0
            }
    443
    0
            size
    444
    0
        }
    445
    }
    446
    447
    impl ArrayAccessor for FixedSizeListArray {
    448
        type Item = ArrayRef;
    449
    450
    0
        fn value(&self, index: usize) -> Self::Item {
    451
    0
            FixedSizeListArray::value(self, index)
    452
    0
        }
    453
    454
    0
        unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
    455
    0
            FixedSizeListArray::value(self, index)
    456
    0
        }
    457
    }
    458
    459
    impl std::fmt::Debug for FixedSizeListArray {
    460
    0
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    461
    0
            write!(f, "FixedSizeListArray<{}>\n[\n", self.value_length())?;
    462
    0
            print_long_array(self, f, |array, index, f| {
    463
    0
                std::fmt::Debug::fmt(&array.value(index), f)
    464
    0
            })?;
    465
    0
            write!(f, "]")
    466
    0
        }
    467
    }
    468
    469
    impl ArrayAccessor for &FixedSizeListArray {
    470
        type Item = ArrayRef;
    471
    472
    0
        fn value(&self, index: usize) -> Self::Item {
    473
    0
            FixedSizeListArray::value(self, index)
    474
    0
        }
    475
    476
    0
        unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
    477
    0
            FixedSizeListArray::value(self, index)
    478
    0
        }
    479
    }
    480
    481
    #[cfg(test)]
    482
    mod tests {
    483
        use arrow_buffer::{bit_util, BooleanBuffer, Buffer};
    484
        use arrow_schema::Field;
    485
    486
        use crate::cast::AsArray;
    487
        use crate::types::Int32Type;
    488
        use crate::{new_empty_array, Int32Array};
    489
    490
        use super::*;
    491
    492
        #[test]
    493
        fn test_fixed_size_list_array() {
    494
            // Construct a value array
    495
            let value_data = ArrayData::builder(DataType::Int32)
    496
                .len(9)
    497
                .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8]))
    498
                .build()
    499
                .unwrap();
    500
    501
            // Construct a list array from the above two
    502
            let list_data_type =
    503
                DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
    504
            let list_data = ArrayData::builder(list_data_type.clone())
    505
                .len(3)
    506
                .add_child_data(value_data.clone())
    507
                .build()
    508
                .unwrap();
    509
            let list_array = FixedSizeListArray::from(list_data);
    510
    511
            assert_eq!(value_data, list_array.values().to_data());
    512
            assert_eq!(DataType::Int32, list_array.value_type());
    513
            assert_eq!(3, list_array.len());
    514
            assert_eq!(0, list_array.null_count());
    515
            assert_eq!(6, list_array.value_offset(2));
    516
            assert_eq!(3, list_array.value_length());
    517
            assert_eq!(0, list_array.value(0).as_primitive::<Int32Type>().value(0));
    518
            for i in 0..3 {
    519
                assert!(list_array.is_valid(i));
    520
                assert!(!list_array.is_null(i));
    521
            }
    522
    523
            // Now test with a non-zero offset
    524
            let list_data = ArrayData::builder(list_data_type)
    525
                .len(2)
    526
                .offset(1)
    527
                .add_child_data(value_data.clone())
    528
                .build()
    529
                .unwrap();
    530
            let list_array = FixedSizeListArray::from(list_data);
    531
    532
            assert_eq!(value_data.slice(3, 6), list_array.values().to_data());
    533
            assert_eq!(DataType::Int32, list_array.value_type());
    534
            assert_eq!(2, list_array.len());
    535
            assert_eq!(0, list_array.null_count());
    536
            assert_eq!(3, list_array.value(0).as_primitive::<Int32Type>().value(0));
    537
            assert_eq!(3, list_array.value_offset(1));
    538
            assert_eq!(3, list_array.value_length());
    539
        }
    540
    541
        #[test]
    542
        #[should_panic(expected = "assertion failed: (offset + length) <= self.len()")]
    543
        // Different error messages, so skip for now
    544
        // https://github.com/apache/arrow-rs/issues/1545
    545
        #[cfg(not(feature = "force_validate"))]
    546
        fn test_fixed_size_list_array_unequal_children() {
    547
            // Construct a value array
    548
            let value_data = ArrayData::builder(DataType::Int32)
    549
                .len(8)
    550
                .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7]))
    551
                .build()
    552
                .unwrap();
    553
    554
            // Construct a list array from the above two
    555
            let list_data_type =
    556
                DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
    557
            let list_data = unsafe {
    558
                ArrayData::builder(list_data_type)
    559
                    .len(3)
    560
                    .add_child_data(value_data)
    561
                    .build_unchecked()
    562
            };
    563
            drop(FixedSizeListArray::from(list_data));
    564
        }
    565
    566
        #[test]
    567
        fn test_fixed_size_list_array_slice() {
    568
            // Construct a value array
    569
            let value_data = ArrayData::builder(DataType::Int32)
    570
                .len(10)
    571
                .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
    572
                .build()
    573
                .unwrap();
    574
    575
            // Set null buts for the nested array:
    576
            //  [[0, 1], null, null, [6, 7], [8, 9]]
    577
            // 01011001 00000001
    578
            let mut null_bits: [u8; 1] = [0; 1];
    579
            bit_util::set_bit(&mut null_bits, 0);
    580
            bit_util::set_bit(&mut null_bits, 3);
    581
            bit_util::set_bit(&mut null_bits, 4);
    582
    583
            // Construct a fixed size list array from the above two
    584
            let list_data_type =
    585
                DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
    586
            let list_data = ArrayData::builder(list_data_type)
    587
                .len(5)
    588
                .add_child_data(value_data.clone())
    589
                .null_bit_buffer(Some(Buffer::from(null_bits)))
    590
                .build()
    591
                .unwrap();
    592
            let list_array = FixedSizeListArray::from(list_data);
    593
    594
            assert_eq!(value_data, list_array.values().to_data());
    595
            assert_eq!(DataType::Int32, list_array.value_type());
    596
            assert_eq!(5, list_array.len());
    597
            assert_eq!(2, list_array.null_count());
    598
            assert_eq!(6, list_array.value_offset(3));
    599
            assert_eq!(2, list_array.value_length());
    600
    601
            let sliced_array = list_array.slice(1, 4);
    602
            assert_eq!(4, sliced_array.len());
    603
            assert_eq!(2, sliced_array.null_count());
    604
    605
            for i in 0..sliced_array.len() {
    606
                if bit_util::get_bit(&null_bits, 1 + i) {
    607
                    assert!(sliced_array.is_valid(i));
    608
                } else {
    609
                    assert!(sliced_array.is_null(i));
    610
                }
    611
            }
    612
    613
            // Check offset and length for each non-null value.
    614
            let sliced_list_array = sliced_array
    615
                .as_any()
    616
                .downcast_ref::<FixedSizeListArray>()
    617
                .unwrap();
    618
            assert_eq!(2, sliced_list_array.value_length());
    619
            assert_eq!(4, sliced_list_array.value_offset(2));
    620
            assert_eq!(6, sliced_list_array.value_offset(3));
    621
        }
    622
    623
        #[test]
    624
        #[should_panic(expected = "the offset of the new Buffer cannot exceed the existing length")]
    625
        fn test_fixed_size_list_array_index_out_of_bound() {
    626
            // Construct a value array
    627
            let value_data = ArrayData::builder(DataType::Int32)
    628
                .len(10)
    629
                .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
    630
                .build()
    631
                .unwrap();
    632
    633
            // Set null buts for the nested array:
    634
            //  [[0, 1], null, null, [6, 7], [8, 9]]
    635
            // 01011001 00000001
    636
            let mut null_bits: [u8; 1] = [0; 1];
    637
            bit_util::set_bit(&mut null_bits, 0);
    638
            bit_util::set_bit(&mut null_bits, 3);
    639
            bit_util::set_bit(&mut null_bits, 4);
    640
    641
            // Construct a fixed size list array from the above two
    642
            let list_data_type =
    643
                DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
    644
            let list_data = ArrayData::builder(list_data_type)
    645
                .len(5)
    646
                .add_child_data(value_data)
    647
                .null_bit_buffer(Some(Buffer::from(null_bits)))
    648
                .build()
    649
                .unwrap();
    650
            let list_array = FixedSizeListArray::from(list_data);
    651
    652
            list_array.value(10);
    653
        }
    654
    655
        #[test]
    656
        fn test_fixed_size_list_constructors() {
    657
            let values = Arc::new(Int32Array::from_iter([
    658
                Some(1),
    659
                Some(2),
    660
                None,
    661
                None,
    662
                Some(3),
    663
                Some(4),
    664
            ]));
    665
    666
            let field = Arc::new(Field::new_list_field(DataType::Int32, true));
    667
            let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), None);
    668
            assert_eq!(list.len(), 3);
    669
    670
            let nulls = NullBuffer::new_null(3);
    671
            let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), Some(nulls));
    672
            assert_eq!(list.len(), 3);
    673
    674
            let list = FixedSizeListArray::new(field.clone(), 4, values.clone(), None);
    675
            assert_eq!(list.len(), 1);
    676
    677
            let err = FixedSizeListArray::try_new(field.clone(), -1, values.clone(), None).unwrap_err();
    678
            assert_eq!(
    679
                err.to_string(),
    680
                "Invalid argument error: Size cannot be negative, got -1"
    681
            );
    682
    683
            let list = FixedSizeListArray::new(field.clone(), 0, values.clone(), None);
    684
            assert_eq!(list.len(), 0);
    685
    686
            let nulls = NullBuffer::new_null(2);
    687
            let err = FixedSizeListArray::try_new(field, 2, values.clone(), Some(nulls)).unwrap_err();
    688
            assert_eq!(err.to_string(), "Invalid argument error: Incorrect length of null buffer for FixedSizeListArray, expected 3 got 2");
    689
    690
            let field = Arc::new(Field::new_list_field(DataType::Int32, false));
    691
            let err = FixedSizeListArray::try_new(field.clone(), 2, values.clone(), None).unwrap_err();
    692
            assert_eq!(err.to_string(), "Invalid argument error: Found unmasked nulls for non-nullable FixedSizeListArray field \"item\"");
    693
    694
            // Valid as nulls in child masked by parent
    695
            let nulls = NullBuffer::new(BooleanBuffer::new(Buffer::from([0b0000101]), 0, 3));
    696
            FixedSizeListArray::new(field, 2, values.clone(), Some(nulls));
    697
    698
            let field = Arc::new(Field::new_list_field(DataType::Int64, true));
    699
            let err = FixedSizeListArray::try_new(field, 2, values, None).unwrap_err();
    700
            assert_eq!(err.to_string(), "Invalid argument error: FixedSizeListArray expected data type Int64 got Int32 for \"item\"");
    701
        }
    702
    703
        #[test]
    704
        fn empty_fixed_size_list() {
    705
            let field = Arc::new(Field::new_list_field(DataType::Int32, true));
    706
            let nulls = NullBuffer::new_null(2);
    707
            let values = new_empty_array(&DataType::Int32);
    708
            let list = FixedSizeListArray::new(field.clone(), 0, values, Some(nulls));
    709
            assert_eq!(list.len(), 2);
    710
        }
    711
    }