Coverage Report

Created: 2025-11-17 14:14

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