## 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_binary_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::iterator::FixedSizeBinaryIter;
    20
    use crate::{Array, ArrayAccessor, ArrayRef, FixedSizeListArray, Scalar};
    21
    use arrow_buffer::buffer::NullBuffer;
    22
    use arrow_buffer::{bit_util, ArrowNativeType, BooleanBuffer, Buffer, MutableBuffer};
    23
    use arrow_data::{ArrayData, ArrayDataBuilder};
    24
    use arrow_schema::{ArrowError, DataType};
    25
    use std::any::Any;
    26
    use std::sync::Arc;
    27
    28
    /// An array of [fixed size binary arrays](https://arrow.apache.org/docs/format/Columnar.html#fixed-size-primitive-layout)
    29
    ///
    30
    /// # Examples
    31
    ///
    32
    /// Create an array from an iterable argument of byte slices.
    33
    ///
    34
    /// ```
    35
    ///    use arrow_array::{Array, FixedSizeBinaryArray};
    36
    ///    let input_arg = vec![ vec![1, 2], vec![3, 4], vec![5, 6] ];
    37
    ///    let arr = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
    38
    ///
    39
    ///    assert_eq!(3, arr.len());
    40
    ///
    41
    /// ```
    42
    /// Create an array from an iterable argument of sparse byte slices.
    43
    /// Sparsity means that the input argument can contain `None` items.
    44
    /// ```
    45
    ///    use arrow_array::{Array, FixedSizeBinaryArray};
    46
    ///    let input_arg = vec![ None, Some(vec![7, 8]), Some(vec![9, 10]), None, Some(vec![13, 14]) ];
    47
    ///    let arr = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
    48
    ///    assert_eq!(5, arr.len())
    49
    ///
    50
    /// ```
    51
    ///
    52
    #[derive(Clone)]
    53
    pub struct FixedSizeBinaryArray {
    54
        data_type: DataType, // Must be DataType::FixedSizeBinary(value_length)
    55
        value_data: Buffer,
    56
        nulls: Option<NullBuffer>,
    57
        len: usize,
    58
        value_length: i32,
    59
    }
    60
    61
    impl FixedSizeBinaryArray {
    62
        /// Create a new [`FixedSizeBinaryArray`] with `size` element size, panicking on failure
    63
        ///
    64
        /// # Panics
    65
        ///
    66
        /// Panics if [`Self::try_new`] returns an error
    67
    0
        pub fn new(size: i32, values: Buffer, nulls: Option<NullBuffer>) -> Self {
    68
    0
            Self::try_new(size, values, nulls).unwrap()
    69
    0
        }
    70
    71
        /// Create a new [`Scalar`] from `value`
    72
        pub fn new_scalar(value: impl AsRef<[u8]>) -> Scalar<Self> {
    73
            let v = value.as_ref();
    74
            Scalar::new(Self::new(v.len() as _, Buffer::from(v), None))
    75
        }
    76
    77
        /// Create a new [`FixedSizeBinaryArray`] from the provided parts, returning an error on failure
    78
        ///
    79
        /// # Errors
    80
        ///
    81
        /// * `size < 0`
    82
        /// * `values.len() / size != nulls.len()`
    83
    13
        pub fn try_new(
    84
    13
            size: i32,
    85
    13
            values: Buffer,
    86
    13
            nulls: Option<NullBuffer>,
    87
    13
        ) -> Result<Self, ArrowError> {
    88
    13
            let data_type = DataType::FixedSizeBinary(size);
    89
    13
            let s = size.to_usize().ok_or_else(|| {0
    90
    0
                ArrowError::InvalidArgumentError(format!("Size cannot be negative, got {size}"))
    91
    0
            })?;
    92
    93
    13
            let len = values.len() / s;
    94
    13
            if let Some(n2) = nulls.as_ref() {
    95
    2
                if n.len() != len {
    96
    0
                    return Err(ArrowError::InvalidArgumentError(format!(
    97
    0
                        "Incorrect length of null buffer for FixedSizeBinaryArray, expected {} got {}",
    98
    0
                        len,
    99
    0
                        n.len(),
    100
    0
                    )));
    101
    2
                }
    102
    11
            }
    103
    104
    13
            Ok(Self {
    105
    13
                data_type,
    106
    13
                value_data: values,
    107
    13
                value_length: size,
    108
    13
                nulls,
    109
    13
                len,
    110
    13
            })
    111
    13
        }
    112
    113
        /// Create a new [`FixedSizeBinaryArray`] of length `len` where all values are null
    114
        ///
    115
        /// # Panics
    116
        ///
    117
        /// Panics if
    118
        ///
    119
        /// * `size < 0`
    120
        /// * `size * len` would overflow `usize`
    121
    0
        pub fn new_null(size: i32, len: usize) -> Self {
    122
    0
            let capacity = size.to_usize().unwrap().checked_mul(len).unwrap();
    123
    0
            Self {
    124
    0
                data_type: DataType::FixedSizeBinary(size),
    125
    0
                value_data: MutableBuffer::new(capacity).into(),
    126
    0
                nulls: Some(NullBuffer::new_null(len)),
    127
    0
                value_length: size,
    128
    0
                len,
    129
    0
            }
    130
    0
        }
    131
    132
        /// Deconstruct this array into its constituent parts
    133
    0
        pub fn into_parts(self) -> (i32, Buffer, Option<NullBuffer>) {
    134
    0
            (self.value_length, self.value_data, self.nulls)
    135
    0
        }
    136
    137
        /// Returns the element at index `i` as a byte slice.
    138
        ///
    139
        /// Note: This method does not check for nulls and the value is arbitrary
    140
        /// (but still well-defined) if [`is_null`](Self::is_null) returns true for the index.
    141
        ///
    142
        /// # Panics
    143
        /// Panics if index `i` is out of bounds.
    144
    3
        pub fn value(&self, i: usize) -> &[u8] {
    145
    3
            assert!(
    146
    3
                i < self.len(),
    147
    0
                "Trying to access an element at index {} from a FixedSizeBinaryArray of length {}",
    148
                i,
    149
    0
                self.len()
    150
            );
    151
    3
            let offset = i + self.offset();
    152
            unsafe {
    153
    3
                let pos = self.value_offset_at(offset);
    154
    3
                std::slice::from_raw_parts(
    155
    3
                    self.value_data.as_ptr().offset(pos as isize),
    156
    3
                    (self.value_offset_at(offset + 1) - pos) as usize,
    157
    3
                )
    158
            }
    159
    3
        }
    160
    161
        /// Returns the element at index `i` as a byte slice.
    162
        ///
    163
        /// Note: This method does not check for nulls and the value is arbitrary
    164
        /// if [`is_null`](Self::is_null) returns true for the index.
    165
        ///
    166
        /// # Safety
    167
        ///
    168
        /// Caller is responsible for ensuring that the index is within the bounds
    169
        /// of the array
    170
    0
        pub unsafe fn value_unchecked(&self, i: usize) -> &[u8] {
    171
    0
            let offset = i + self.offset();
    172
    0
            let pos = self.value_offset_at(offset);
    173
    0
            std::slice::from_raw_parts(
    174
    0
                self.value_data.as_ptr().offset(pos as isize),
    175
    0
                (self.value_offset_at(offset + 1) - pos) as usize,
    176
    0
            )
    177
    0
        }
    178
    179
        /// Returns the offset for the element at index `i`.
    180
        ///
    181
        /// Note this doesn't do any bound checking, for performance reason.
    182
        #[inline]
    183
    0
        pub fn value_offset(&self, i: usize) -> i32 {
    184
    0
            self.value_offset_at(self.offset() + i)
    185
    0
        }
    186
    187
        /// Returns the length for an element.
    188
        ///
    189
        /// All elements have the same length as the array is a fixed size.
    190
        #[inline]
    191
    3
        pub fn value_length(&self) -> i32 {
    192
    3
            self.value_length
    193
    3
        }
    194
    195
        /// Returns the values of this array.
    196
        ///
    197
        /// Unlike [`Self::value_data`] this returns the [`Buffer`]
    198
        /// allowing for zero-copy cloning.
    199
        #[inline]
    200
    0
        pub fn values(&self) -> &Buffer {
    201
    0
            &self.value_data
    202
    0
        }
    203
    204
        /// Returns the raw value data.
    205
    0
        pub fn value_data(&self) -> &[u8] {
    206
    0
            self.value_data.as_slice()
    207
    0
        }
    208
    209
        /// Returns a zero-copy slice of this array with the indicated offset and length.
    210
    4
        pub fn slice(&self, offset: usize, len: usize) -> Self {
    211
    4
            assert!(
    212
    4
                offset.saturating_add(len) <= self.len,
    213
    0
                "the length + offset of the sliced FixedSizeBinaryArray cannot exceed the existing length"
    214
            );
    215
    216
    4
            let size = self.value_length as usize;
    217
    218
            Self {
    219
    4
                data_type: self.data_type.clone(),
    220
    4
                nulls: self.nulls.as_ref().map(|n| n1.slice1(offset1, len1)),
    221
    4
                value_length: self.value_length,
    222
    4
                value_data: self.value_data.slice_with_length(offset * size, len * size),
    223
    4
                len,
    224
            }
    225
    4
        }
    226
    227
        /// Create an array from an iterable argument of sparse byte slices.
    228
        /// Sparsity means that items returned by the iterator are optional, i.e input argument can
    229
        /// contain `None` items.
    230
        ///
    231
        /// # Examples
    232
        ///
    233
        /// ```
    234
        /// use arrow_array::FixedSizeBinaryArray;
    235
        /// let input_arg = vec![
    236
        ///     None,
    237
        ///     Some(vec![7, 8]),
    238
        ///     Some(vec![9, 10]),
    239
        ///     None,
    240
        ///     Some(vec![13, 14]),
    241
        ///     None,
    242
        /// ];
    243
        /// let array = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.into_iter()).unwrap();
    244
        /// ```
    245
        ///
    246
        /// # Errors
    247
        ///
    248
        /// Returns error if argument has length zero, or sizes of nested slices don't match.
    249
        #[deprecated(
    250
            since = "28.0.0",
    251
            note = "This function will fail if the iterator produces only None values; prefer `try_from_sparse_iter_with_size`"
    252
        )]
    253
    0
        pub fn try_from_sparse_iter<T, U>(mut iter: T) -> Result<Self, ArrowError>
    254
    0
        where
    255
    0
            T: Iterator<Item = Option<U>>,
    256
    0
            U: AsRef<[u8]>,
    257
        {
    258
    0
            let mut len = 0;
    259
    0
            let mut size = None;
    260
    0
            let mut byte = 0;
    261
    262
    0
            let iter_size_hint = iter.size_hint().0;
    263
    0
            let mut null_buf = MutableBuffer::new(bit_util::ceil(iter_size_hint, 8));
    264
    0
            let mut buffer = MutableBuffer::new(0);
    265
    266
    0
            let mut prepend = 0;
    267
    0
            iter.try_for_each(|item| -> Result<(), ArrowError> {
    268
                // extend null bitmask by one byte per each 8 items
    269
    0
                if byte == 0 {
    270
    0
                    null_buf.push(0u8);
    271
    0
                    byte = 8;
    272
    0
                }
    273
    0
                byte -= 1;
    274
    275
    0
                if let Some(slice) = item {
    276
    0
                    let slice = slice.as_ref();
    277
    0
                    if let Some(size) = size {
    278
    0
                        if size != slice.len() {
    279
    0
                            return Err(ArrowError::InvalidArgumentError(format!(
    280
    0
                                "Nested array size mismatch: one is {}, and the other is {}",
    281
    0
                                size,
    282
    0
                                slice.len()
    283
    0
                            )));
    284
    0
                        }
    285
    0
                    } else {
    286
    0
                        let len = slice.len();
    287
    0
                        size = Some(len);
    288
    0
                        // Now that we know how large each element is we can reserve
    289
    0
                        // sufficient capacity in the underlying mutable buffer for
    290
    0
                        // the data.
    291
    0
                        buffer.reserve(iter_size_hint * len);
    292
    0
                        buffer.extend_zeros(slice.len() * prepend);
    293
    0
                    }
    294
    0
                    bit_util::set_bit(null_buf.as_slice_mut(), len);
    295
    0
                    buffer.extend_from_slice(slice);
    296
    0
                } else if let Some(size) = size {
    297
    0
                    buffer.extend_zeros(size);
    298
    0
                } else {
    299
    0
                    prepend += 1;
    300
    0
                }
    301
    302
    0
                len += 1;
    303
    304
    0
                Ok(())
    305
    0
            })?;
    306
    307
    0
            if len == 0 {
    308
    0
                return Err(ArrowError::InvalidArgumentError(
    309
    0
                    "Input iterable argument has no data".to_owned(),
    310
    0
                ));
    311
    0
            }
    312
    313
    0
            let null_buf = BooleanBuffer::new(null_buf.into(), 0, len);
    314
    0
            let nulls = Some(NullBuffer::new(null_buf)).filter(|n| n.null_count() > 0);
    315
    316
    0
            let size = size.unwrap_or(0) as i32;
    317
    0
            Ok(Self {
    318
    0
                data_type: DataType::FixedSizeBinary(size),
    319
    0
                value_data: buffer.into(),
    320
    0
                nulls,
    321
    0
                value_length: size,
    322
    0
                len,
    323
    0
            })
    324
    0
        }
    325
    326
        /// Create an array from an iterable argument of sparse byte slices.
    327
        /// Sparsity means that items returned by the iterator are optional, i.e input argument can
    328
        /// contain `None` items. In cases where the iterator returns only `None` values, this
    329
        /// also takes a size parameter to ensure that the a valid FixedSizeBinaryArray is still
    330
        /// created.
    331
        ///
    332
        /// # Examples
    333
        ///
    334
        /// ```
    335
        /// use arrow_array::FixedSizeBinaryArray;
    336
        /// let input_arg = vec![
    337
        ///     None,
    338
        ///     Some(vec![7, 8]),
    339
        ///     Some(vec![9, 10]),
    340
        ///     None,
    341
        ///     Some(vec![13, 14]),
    342
        ///     None,
    343
        /// ];
    344
        /// let array = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
    345
        /// ```
    346
        ///
    347
        /// # Errors
    348
        ///
    349
        /// Returns error if argument has length zero, or sizes of nested slices don't match.
    350
    2
        pub fn try_from_sparse_iter_with_size<T, U>(mut iter: T, size: i32) -> Result<Self, ArrowError>
    351
    2
        where
    352
    2
            T: Iterator<Item = Option<U>>,
    353
    2
            U: AsRef<[u8]>,
    354
        {
    355
    2
            let mut len = 0;
    356
    2
            let mut byte = 0;
    357
    358
    2
            let iter_size_hint = iter.size_hint().0;
    359
    2
            let mut null_buf = MutableBuffer::new(bit_util::ceil(iter_size_hint, 8));
    360
    2
            let mut buffer = MutableBuffer::new(iter_size_hint * (size as usize));
    361
    362
    6
            iter2.try_for_each2(|item| -> Result<(), ArrowError> {
    363
                // extend null bitmask by one byte per each 8 items
    364
    6
                if byte == 0 {
    365
    2
                    null_buf.push(0u8);
    366
    2
                    byte = 8;
    367
    4
                }
    368
    6
                byte -= 1;
    369
    370
    6
                if let Some(slice5) = item {
    371
    5
                    let slice = slice.as_ref();
    372
    5
                    if size as usize != slice.len() {
    373
    0
                        return Err(ArrowError::InvalidArgumentError(format!(
    374
    0
                            "Nested array size mismatch: one is {}, and the other is {}",
    375
    0
                            size,
    376
    0
                            slice.len()
    377
    0
                        )));
    378
    5
                    }
    379
    380
    5
                    bit_util::set_bit(null_buf.as_slice_mut(), len);
    381
    5
                    buffer.extend_from_slice(slice);
    382
    1
                } else {
    383
    1
                    buffer.extend_zeros(size as usize);
    384
    1
                }
    385
    386
    6
                len += 1;
    387
    388
    6
                Ok(())
    389
    6
            })?0;
    390
    391
    2
            let null_buf = BooleanBuffer::new(null_buf.into(), 0, len);
    392
    2
            let nulls = Some(NullBuffer::new(null_buf)).filter(|n| n.null_count() > 0);
    393
    394
    2
            Ok(Self {
    395
    2
                data_type: DataType::FixedSizeBinary(size),
    396
    2
                value_data: buffer.into(),
    397
    2
                nulls,
    398
    2
                len,
    399
    2
                value_length: size,
    400
    2
            })
    401
    2
        }
    402
    403
        /// Create an array from an iterable argument of byte slices.
    404
        ///
    405
        /// # Examples
    406
        ///
    407
        /// ```
    408
        /// use arrow_array::FixedSizeBinaryArray;
    409
        /// let input_arg = vec![
    410
        ///     vec![1, 2],
    411
        ///     vec![3, 4],
    412
        ///     vec![5, 6],
    413
        /// ];
    414
        /// let array = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
    415
        /// ```
    416
        ///
    417
        /// # Errors
    418
        ///
    419
        /// Returns error if argument has length zero, or sizes of nested slices don't match.
    420
    2
        pub fn try_from_iter<T, U>(mut iter: T) -> Result<Self, ArrowError>
    421
    2
        where
    422
    2
            T: Iterator<Item = U>,
    423
    2
            U: AsRef<[u8]>,
    424
        {
    425
    2
            let mut len = 0;
    426
    2
            let mut size = None;
    427
    2
            let iter_size_hint = iter.size_hint().0;
    428
    2
            let mut buffer = MutableBuffer::new(0);
    429
    430
    4
            iter2.try_for_each2(|item| -> Result<(), ArrowError> {
    431
    4
                let slice = item.as_ref();
    432
    4
                if let Some(size2) = size {
    433
    2
                    if size != slice.len() {
    434
    0
                        return Err(ArrowError::InvalidArgumentError(format!(
    435
    0
                            "Nested array size mismatch: one is {}, and the other is {}",
    436
    0
                            size,
    437
    0
                            slice.len()
    438
    0
                        )));
    439
    2
                    }
    440
    2
                } else {
    441
    2
                    let len = slice.len();
    442
    2
                    size = Some(len);
    443
    2
                    buffer.reserve(iter_size_hint * len);
    444
    2
                }
    445
    446
    4
                buffer.extend_from_slice(slice);
    447
    448
    4
                len += 1;
    449
    450
    4
                Ok(())
    451
    4
            })?0;
    452
    453
    2
            if len == 0 {
    454
    0
                return Err(ArrowError::InvalidArgumentError(
    455
    0
                    "Input iterable argument has no data".to_owned(),
    456
    0
                ));
    457
    2
            }
    458
    459
    2
            let size = size.unwrap_or(0).try_into().unwrap();
    460
    2
            Ok(Self {
    461
    2
                data_type: DataType::FixedSizeBinary(size),
    462
    2
                value_data: buffer.into(),
    463
    2
                nulls: None,
    464
    2
                value_length: size,
    465
    2
                len,
    466
    2
            })
    467
    2
        }
    468
    469
        #[inline]
    470
    6
        fn value_offset_at(&self, i: usize) -> i32 {
    471
    6
            self.value_length * i as i32
    472
    6
        }
    473
    474
        /// constructs a new iterator
    475
    0
        pub fn iter(&self) -> FixedSizeBinaryIter<'_> {
    476
    0
            FixedSizeBinaryIter::new(self)
    477
    0
        }
    478
    }
    479
    480
    impl From<ArrayData> for FixedSizeBinaryArray {
    481
    3
        fn from(data: ArrayData) -> Self {
    482
    3
            assert_eq!(
    483
    3
                data.buffers().len(),
    484
                1,
    485
    0
                "FixedSizeBinaryArray data should contain 1 buffer only (values)"
    486
            );
    487
    3
            let value_length = match data.data_type() {
    488
    3
                DataType::FixedSizeBinary(len) => *len,
    489
    0
                _ => panic!("Expected data type to be FixedSizeBinary"),
    490
            };
    491
    492
    3
            let size = value_length as usize;
    493
    3
            let value_data =
    494
    3
                data.buffers()[0].slice_with_length(data.offset() * size, data.len() * size);
    495
    496
    3
            Self {
    497
    3
                data_type: data.data_type().clone(),
    498
    3
                nulls: data.nulls().cloned(),
    499
    3
                len: data.len(),
    500
    3
                value_data,
    501
    3
                value_length,
    502
    3
            }
    503
    3
        }
    504
    }
    505
    506
    impl From<FixedSizeBinaryArray> for ArrayData {
    507
    20
        fn from(array: FixedSizeBinaryArray) -> Self {
    508
    20
            let builder = ArrayDataBuilder::new(array.data_type)
    509
    20
                .len(array.len)
    510
    20
                .buffers(vec![array.value_data])
    511
    20
                .nulls(array.nulls);
    512
    513
    20
            unsafe { builder.build_unchecked() }
    514
    20
        }
    515
    }
    516
    517
    /// Creates a `FixedSizeBinaryArray` from `FixedSizeList<u8>` array
    518
    impl From<FixedSizeListArray> for FixedSizeBinaryArray {
    519
    0
        fn from(v: FixedSizeListArray) -> Self {
    520
    0
            let value_len = v.value_length();
    521
    0
            let v = v.into_data();
    522
    0
            assert_eq!(
    523
    0
                v.child_data().len(),
    524
                1,
    525
    0
                "FixedSizeBinaryArray can only be created from list array of u8 values \
    526
    0
                 (i.e. FixedSizeList<PrimitiveArray<u8>>)."
    527
            );
    528
    0
            let child_data = &v.child_data()[0];
    529
    530
    0
            assert_eq!(
    531
    0
                child_data.child_data().len(),
    532
                0,
    533
    0
                "FixedSizeBinaryArray can only be created from list array of u8 values \
    534
    0
                 (i.e. FixedSizeList<PrimitiveArray<u8>>)."
    535
            );
    536
    0
            assert_eq!(
    537
    0
                child_data.data_type(),
    538
                &DataType::UInt8,
    539
    0
                "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays, mismatched data types."
    540
            );
    541
    0
            assert_eq!(
    542
    0
                child_data.null_count(),
    543
                0,
    544
    0
                "The child array cannot contain null values."
    545
            );
    546
    547
    0
            let builder = ArrayData::builder(DataType::FixedSizeBinary(value_len))
    548
    0
                .len(v.len())
    549
    0
                .offset(v.offset())
    550
    0
                .add_buffer(child_data.buffers()[0].slice(child_data.offset()))
    551
    0
                .nulls(v.nulls().cloned());
    552
    553
    0
            let data = unsafe { builder.build_unchecked() };
    554
    0
            Self::from(data)
    555
    0
        }
    556
    }
    557
    558
    impl From<Vec<Option<&[u8]>>> for FixedSizeBinaryArray {
    559
    0
        fn from(v: Vec<Option<&[u8]>>) -> Self {
    560
            #[allow(deprecated)]
    561
    0
            Self::try_from_sparse_iter(v.into_iter()).unwrap()
    562
    0
        }
    563
    }
    564
    565
    impl From<Vec<&[u8]>> for FixedSizeBinaryArray {
    566
    0
        fn from(v: Vec<&[u8]>) -> Self {
    567
    0
            Self::try_from_iter(v.into_iter()).unwrap()
    568
    0
        }
    569
    }
    570
    571
    impl<const N: usize> From<Vec<&[u8; N]>> for FixedSizeBinaryArray {
    572
        fn from(v: Vec<&[u8; N]>) -> Self {
    573
            Self::try_from_iter(v.into_iter()).unwrap()
    574
        }
    575
    }
    576
    577
    impl std::fmt::Debug for FixedSizeBinaryArray {
    578
    0
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    579
    0
            write!(f, "FixedSizeBinaryArray<{}>\n[\n", self.value_length())?;
    580
    0
            print_long_array(self, f, |array, index, f| {
    581
    0
                std::fmt::Debug::fmt(&array.value(index), f)
    582
    0
            })?;
    583
    0
            write!(f, "]")
    584
    0
        }
    585
    }
    586
    587
    impl Array for FixedSizeBinaryArray {
    588
    4
        fn as_any(&self) -> &dyn Any {
    589
    4
            self
    590
    4
        }
    591
    592
    20
        fn to_data(&self) -> ArrayData {
    593
    20
            self.clone().into()
    594
    20
        }
    595
    596
    0
        fn into_data(self) -> ArrayData {
    597
    0
            self.into()
    598
    0
        }
    599
    600
    26
        fn data_type(&self) -> &DataType {
    601
    26
            &self.data_type
    602
    26
        }
    603
    604
    4
        fn slice(&self, offset: usize, length: usize) -> ArrayRef {
    605
    4
            Arc::new(self.slice(offset, length))
    606
    4
        }
    607
    608
    48
        fn len(&self) -> usize {
    609
    48
            self.len
    610
    48
        }
    611
    612
    0
        fn is_empty(&self) -> bool {
    613
    0
            self.len == 0
    614
    0
        }
    615
    616
    0
        fn shrink_to_fit(&mut self) {
    617
    0
            self.value_data.shrink_to_fit();
    618
    0
            if let Some(nulls) = &mut self.nulls {
    619
    0
                nulls.shrink_to_fit();
    620
    0
            }
    621
    0
        }
    622
    623
    3
        fn offset(&self) -> usize {
    624
    3
            0
    625
    3
        }
    626
    627
    14
        fn nulls(&self) -> Option<&NullBuffer> {
    628
    14
            self.nulls.as_ref()
    629
    14
        }
    630
    631
    0
        fn logical_null_count(&self) -> usize {
    632
            // More efficient that the default implementation
    633
    0
            self.null_count()
    634
    0
        }
    635
    636
    0
        fn get_buffer_memory_size(&self) -> usize {
    637
    0
            let mut sum = self.value_data.capacity();
    638
    0
            if let Some(n) = &self.nulls {
    639
    0
                sum += n.buffer().capacity();
    640
    0
            }
    641
    0
            sum
    642
    0
        }
    643
    644
    0
        fn get_array_memory_size(&self) -> usize {
    645
    0
            std::mem::size_of::<Self>() + self.get_buffer_memory_size()
    646
    0
        }
    647
    }
    648
    649
    impl<'a> ArrayAccessor for &'a FixedSizeBinaryArray {
    650
        type Item = &'a [u8];
    651
    652
    0
        fn value(&self, index: usize) -> Self::Item {
    653
    0
            FixedSizeBinaryArray::value(self, index)
    654
    0
        }
    655
    656
    0
        unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
    657
    0
            FixedSizeBinaryArray::value_unchecked(self, index)
    658
    0
        }
    659
    }
    660
    661
    impl<'a> IntoIterator for &'a FixedSizeBinaryArray {
    662
        type Item = Option<&'a [u8]>;
    663
        type IntoIter = FixedSizeBinaryIter<'a>;
    664
    665
    0
        fn into_iter(self) -> Self::IntoIter {
    666
    0
            FixedSizeBinaryIter::<'a>::new(self)
    667
    0
        }
    668
    }
    669
    670
    #[cfg(test)]
    671
    mod tests {
    672
        use crate::RecordBatch;
    673
        use arrow_schema::{Field, Schema};
    674
    675
        use super::*;
    676
    677
        #[test]
    678
        fn test_fixed_size_binary_array() {
    679
            let values: [u8; 15] = *b"hellotherearrow";
    680
    681
            let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
    682
                .len(3)
    683
                .add_buffer(Buffer::from(&values))
    684
                .build()
    685
                .unwrap();
    686
            let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
    687
            assert_eq!(3, fixed_size_binary_array.len());
    688
            assert_eq!(0, fixed_size_binary_array.null_count());
    689
            assert_eq!(
    690
                [b'h', b'e', b'l', b'l', b'o'],
    691
                fixed_size_binary_array.value(0)
    692
            );
    693
            assert_eq!(
    694
                [b't', b'h', b'e', b'r', b'e'],
    695
                fixed_size_binary_array.value(1)
    696
            );
    697
            assert_eq!(
    698
                [b'a', b'r', b'r', b'o', b'w'],
    699
                fixed_size_binary_array.value(2)
    700
            );
    701
            assert_eq!(5, fixed_size_binary_array.value_length());
    702
            assert_eq!(10, fixed_size_binary_array.value_offset(2));
    703
            for i in 0..3 {
    704
                assert!(fixed_size_binary_array.is_valid(i));
    705
                assert!(!fixed_size_binary_array.is_null(i));
    706
            }
    707
    708
            // Test binary array with offset
    709
            let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
    710
                .len(2)
    711
                .offset(1)
    712
                .add_buffer(Buffer::from(&values))
    713
                .build()
    714
                .unwrap();
    715
            let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
    716
            assert_eq!(
    717
                [b't', b'h', b'e', b'r', b'e'],
    718
                fixed_size_binary_array.value(0)
    719
            );
    720
            assert_eq!(
    721
                [b'a', b'r', b'r', b'o', b'w'],
    722
                fixed_size_binary_array.value(1)
    723
            );
    724
            assert_eq!(2, fixed_size_binary_array.len());
    725
            assert_eq!(0, fixed_size_binary_array.value_offset(0));
    726
            assert_eq!(5, fixed_size_binary_array.value_length());
    727
            assert_eq!(5, fixed_size_binary_array.value_offset(1));
    728
        }
    729
    730
        #[test]
    731
        fn test_fixed_size_binary_array_from_fixed_size_list_array() {
    732
            let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
    733
            let values_data = ArrayData::builder(DataType::UInt8)
    734
                .len(12)
    735
                .offset(2)
    736
                .add_buffer(Buffer::from_slice_ref(values))
    737
                .build()
    738
                .unwrap();
    739
            // [null, [10, 11, 12, 13]]
    740
            let array_data = unsafe {
    741
                ArrayData::builder(DataType::FixedSizeList(
    742
                    Arc::new(Field::new_list_field(DataType::UInt8, false)),
    743
                    4,
    744
                ))
    745
                .len(2)
    746
                .offset(1)
    747
                .add_child_data(values_data)
    748
                .null_bit_buffer(Some(Buffer::from_slice_ref([0b101])))
    749
                .build_unchecked()
    750
            };
    751
            let list_array = FixedSizeListArray::from(array_data);
    752
            let binary_array = FixedSizeBinaryArray::from(list_array);
    753
    754
            assert_eq!(2, binary_array.len());
    755
            assert_eq!(1, binary_array.null_count());
    756
            assert!(binary_array.is_null(0));
    757
            assert!(binary_array.is_valid(1));
    758
            assert_eq!(&[10, 11, 12, 13], binary_array.value(1));
    759
        }
    760
    761
        #[test]
    762
        #[should_panic(
    763
            expected = "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays"
    764
        )]
    765
        // Different error messages, so skip for now
    766
        // https://github.com/apache/arrow-rs/issues/1545
    767
        #[cfg(not(feature = "force_validate"))]
    768
        fn test_fixed_size_binary_array_from_incorrect_fixed_size_list_array() {
    769
            let values: [u32; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
    770
            let values_data = ArrayData::builder(DataType::UInt32)
    771
                .len(12)
    772
                .add_buffer(Buffer::from_slice_ref(values))
    773
                .build()
    774
                .unwrap();
    775
    776
            let array_data = unsafe {
    777
                ArrayData::builder(DataType::FixedSizeList(
    778
                    Arc::new(Field::new_list_field(DataType::Binary, false)),
    779
                    4,
    780
                ))
    781
                .len(3)
    782
                .add_child_data(values_data)
    783
                .build_unchecked()
    784
            };
    785
            let list_array = FixedSizeListArray::from(array_data);
    786
            drop(FixedSizeBinaryArray::from(list_array));
    787
        }
    788
    789
        #[test]
    790
        #[should_panic(expected = "The child array cannot contain null values.")]
    791
        fn test_fixed_size_binary_array_from_fixed_size_list_array_with_child_nulls_failed() {
    792
            let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
    793
            let values_data = ArrayData::builder(DataType::UInt8)
    794
                .len(12)
    795
                .add_buffer(Buffer::from_slice_ref(values))
    796
                .null_bit_buffer(Some(Buffer::from_slice_ref([0b101010101010])))
    797
                .build()
    798
                .unwrap();
    799
    800
            let array_data = unsafe {
    801
                ArrayData::builder(DataType::FixedSizeList(
    802
                    Arc::new(Field::new_list_field(DataType::UInt8, false)),
    803
                    4,
    804
                ))
    805
                .len(3)
    806
                .add_child_data(values_data)
    807
                .build_unchecked()
    808
            };
    809
            let list_array = FixedSizeListArray::from(array_data);
    810
            drop(FixedSizeBinaryArray::from(list_array));
    811
        }
    812
    813
        #[test]
    814
        fn test_fixed_size_binary_array_fmt_debug() {
    815
            let values: [u8; 15] = *b"hellotherearrow";
    816
    817
            let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
    818
                .len(3)
    819
                .add_buffer(Buffer::from(&values))
    820
                .build()
    821
                .unwrap();
    822
            let arr = FixedSizeBinaryArray::from(array_data);
    823
            assert_eq!(
    824
                "FixedSizeBinaryArray<5>\n[\n  [104, 101, 108, 108, 111],\n  [116, 104, 101, 114, 101],\n  [97, 114, 114, 111, 119],\n]",
    825
                format!("{arr:?}")
    826
            );
    827
        }
    828
    829
        #[test]
    830
        fn test_fixed_size_binary_array_from_iter() {
    831
            let input_arg = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
    832
            let arr = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
    833
    834
            assert_eq!(2, arr.value_length());
    835
            assert_eq!(3, arr.len())
    836
        }
    837
    838
        #[test]
    839
        fn test_all_none_fixed_size_binary_array_from_sparse_iter() {
    840
            let none_option: Option<[u8; 32]> = None;
    841
            let input_arg = vec![none_option, none_option, none_option];
    842
            #[allow(deprecated)]
    843
            let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.into_iter()).unwrap();
    844
            assert_eq!(0, arr.value_length());
    845
            assert_eq!(3, arr.len())
    846
        }
    847
    848
        #[test]
    849
        fn test_fixed_size_binary_array_from_sparse_iter() {
    850
            let input_arg = vec![
    851
                None,
    852
                Some(vec![7, 8]),
    853
                Some(vec![9, 10]),
    854
                None,
    855
                Some(vec![13, 14]),
    856
            ];
    857
            #[allow(deprecated)]
    858
            let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.iter().cloned()).unwrap();
    859
            assert_eq!(2, arr.value_length());
    860
            assert_eq!(5, arr.len());
    861
    862
            let arr =
    863
                FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
    864
            assert_eq!(2, arr.value_length());
    865
            assert_eq!(5, arr.len());
    866
        }
    867
    868
        #[test]
    869
        fn test_fixed_size_binary_array_from_sparse_iter_with_size_all_none() {
    870
            let input_arg = vec![None, None, None, None, None] as Vec<Option<Vec<u8>>>;
    871
    872
            let arr = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 16)
    873
                .unwrap();
    874
            assert_eq!(16, arr.value_length());
    875
            assert_eq!(5, arr.len())
    876
        }
    877
    878
        #[test]
    879
        fn test_fixed_size_binary_array_from_vec() {
    880
            let values = vec!["one".as_bytes(), b"two", b"six", b"ten"];
    881
            let array = FixedSizeBinaryArray::from(values);
    882
            assert_eq!(array.len(), 4);
    883
            assert_eq!(array.null_count(), 0);
    884
            assert_eq!(array.logical_null_count(), 0);
    885
            assert_eq!(array.value(0), b"one");
    886
            assert_eq!(array.value(1), b"two");
    887
            assert_eq!(array.value(2), b"six");
    888
            assert_eq!(array.value(3), b"ten");
    889
            assert!(!array.is_null(0));
    890
            assert!(!array.is_null(1));
    891
            assert!(!array.is_null(2));
    892
            assert!(!array.is_null(3));
    893
        }
    894
    895
        #[test]
    896
        #[should_panic(expected = "Nested array size mismatch: one is 3, and the other is 5")]
    897
        fn test_fixed_size_binary_array_from_vec_incorrect_length() {
    898
            let values = vec!["one".as_bytes(), b"two", b"three", b"four"];
    899
            let _ = FixedSizeBinaryArray::from(values);
    900
        }
    901
    902
        #[test]
    903
        fn test_fixed_size_binary_array_from_opt_vec() {
    904
            let values = vec![
    905
                Some("one".as_bytes()),
    906
                Some(b"two"),
    907
                None,
    908
                Some(b"six"),
    909
                Some(b"ten"),
    910
            ];
    911
            let array = FixedSizeBinaryArray::from(values);
    912
            assert_eq!(array.len(), 5);
    913
            assert_eq!(array.value(0), b"one");
    914
            assert_eq!(array.value(1), b"two");
    915
            assert_eq!(array.value(3), b"six");
    916
            assert_eq!(array.value(4), b"ten");
    917
            assert!(!array.is_null(0));
    918
            assert!(!array.is_null(1));
    919
            assert!(array.is_null(2));
    920
            assert!(!array.is_null(3));
    921
            assert!(!array.is_null(4));
    922
        }
    923
    924
        #[test]
    925
        #[should_panic(expected = "Nested array size mismatch: one is 3, and the other is 5")]
    926
        fn test_fixed_size_binary_array_from_opt_vec_incorrect_length() {
    927
            let values = vec![
    928
                Some("one".as_bytes()),
    929
                Some(b"two"),
    930
                None,
    931
                Some(b"three"),
    932
                Some(b"four"),
    933
            ];
    934
            let _ = FixedSizeBinaryArray::from(values);
    935
        }
    936
    937
        #[test]
    938
        fn fixed_size_binary_array_all_null() {
    939
            let data = vec![None] as Vec<Option<String>>;
    940
            let array =
    941
                FixedSizeBinaryArray::try_from_sparse_iter_with_size(data.into_iter(), 0).unwrap();
    942
            array
    943
                .into_data()
    944
                .validate_full()
    945
                .expect("All null array has valid array data");
    946
        }
    947
    948
        #[test]
    949
        // Test for https://github.com/apache/arrow-rs/issues/1390
    950
        fn fixed_size_binary_array_all_null_in_batch_with_schema() {
    951
            let schema = Schema::new(vec![Field::new("a", DataType::FixedSizeBinary(2), true)]);
    952
    953
            let none_option: Option<[u8; 2]> = None;
    954
            let item = FixedSizeBinaryArray::try_from_sparse_iter_with_size(
    955
                vec![none_option, none_option, none_option].into_iter(),
    956
                2,
    957
            )
    958
            .unwrap();
    959
    960
            // Should not panic
    961
            RecordBatch::try_new(Arc::new(schema), vec![Arc::new(item)]).unwrap();
    962
        }
    963
    964
        #[test]
    965
        #[should_panic(
    966
            expected = "Trying to access an element at index 4 from a FixedSizeBinaryArray of length 3"
    967
        )]
    968
        fn test_fixed_size_binary_array_get_value_index_out_of_bound() {
    969
            let values = vec![Some("one".as_bytes()), Some(b"two"), None];
    970
            let array = FixedSizeBinaryArray::from(values);
    971
    972
            array.value(4);
    973
        }
    974
    975
        #[test]
    976
        fn test_constructors() {
    977
            let buffer = Buffer::from_vec(vec![0_u8; 10]);
    978
            let a = FixedSizeBinaryArray::new(2, buffer.clone(), None);
    979
            assert_eq!(a.len(), 5);
    980
    981
            let nulls = NullBuffer::new_null(5);
    982
            FixedSizeBinaryArray::new(2, buffer.clone(), Some(nulls));
    983
    984
            let a = FixedSizeBinaryArray::new(3, buffer.clone(), None);
    985
            assert_eq!(a.len(), 3);
    986
    987
            let nulls = NullBuffer::new_null(3);
    988
            FixedSizeBinaryArray::new(3, buffer.clone(), Some(nulls));
    989
    990
            let err = FixedSizeBinaryArray::try_new(-1, buffer.clone(), None).unwrap_err();
    991
    992
            assert_eq!(
    993
                err.to_string(),
    994
                "Invalid argument error: Size cannot be negative, got -1"
    995
            );
    996
    997
            let nulls = NullBuffer::new_null(3);
    998
            let err = FixedSizeBinaryArray::try_new(2, buffer, Some(nulls)).unwrap_err();
    999
            assert_eq!(err.to_string(), "Invalid argument error: Incorrect length of null buffer for FixedSizeBinaryArray, expected 5 got 3");
    1000
        }
    1001
    }