Skip to main content

arrow_array/array/
fixed_size_binary_array.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5use crate::array::print_long_array;
6use crate::iterator::FixedSizeBinaryIter;
7use crate::{Array, ArrayAccessor, ArrayRef, FixedSizeListArray, Scalar};
8use arrow_buffer::buffer::NullBuffer;
9use arrow_buffer::{ArrowNativeType, Buffer, MutableBuffer, bit_util};
10use arrow_data::{ArrayData, ArrayDataBuilder};
11use arrow_schema::{ArrowError, DataType};
12use std::any::Any;
13use std::sync::Arc;
14
15/// An array of [fixed-size binary values](https://arrow.apache.org/docs/format/Columnar.html#fixed-size-primitive-layout)
16///
17/// Each element in a [`FixedSizeBinaryArray`] has `value_length` bytes, where
18/// `value_length` is defined by the schema.
19///
20/// This array type is useful for storing fixed-length values such as 16-byte
21/// UUIDs (`value_length = 16`).
22///
23/// # Layout
24///
25/// Values in a [`FixedSizeBinaryArray`] are stored contiguously in a single
26/// buffer. The byte offset for the `i`-th element can be calculated as
27/// `i * value_length`.
28///
29/// Nulls are stored in a standard optional Arrow [`NullBuffer`].
30///
31/// For example, a 100-value [`FixedSizeBinaryArray`] with `value_length = 12`
32/// is shown below.
33///
34/// ```text
35/// ┌──────────────────────────────────────────┐
36/// │ Computed byte offsets                    │
37/// │          ┌──────────────────────┐ ┌────┐ │
38/// │          │┌────────────────────┐│ │    │ │
39/// │       0  ││value 0  (12 bytes) ││ │ 1  │ │
40/// │          │├────────────────────┤│ │    │ │
41/// │       12 ││value 1  (12 bytes) ││ │ 0  │ │
42/// │          │├────────────────────┤│ │    │ │
43/// │       24 ││value 2  (12 bytes) ││ │ 1  │ │
44/// │          │└────────────────────┘│ │    │ │
45/// │          │         ...          │ │... │ │
46/// │          │┌───────────────────┐ │ │    │ │
47/// │     1188 ││value 99 (12 bytes)│ │ │ 1  │ │
48/// │          │└───────────────────┘ │ │    │ │
49/// │          └──────────────────────┘ └────┘ │
50/// │           value_data              nulls  │
51/// └──────────────────────────────────────────┘
52/// ```
53///
54/// # Examples
55///
56/// Create an array from an iterable argument of byte slices.
57///
58/// ```
59///    use arrow_array::{Array, FixedSizeBinaryArray};
60///    let input_arg = vec![ vec![1, 2], vec![3, 4], vec![5, 6] ];
61///    let arr = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
62///
63///    assert_eq!(3, arr.len());
64///
65/// ```
66/// Create an array from an iterable argument of sparse byte slices.
67/// Sparsity means that the input argument can contain `None` items.
68/// ```
69///    use arrow_array::{Array, FixedSizeBinaryArray};
70///    let input_arg = vec![ None, Some(vec![7, 8]), Some(vec![9, 10]), None, Some(vec![13, 14]) ];
71///    let arr = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
72///    assert_eq!(5, arr.len())
73///
74/// ```
75///
76#[derive(Clone)]
77pub struct FixedSizeBinaryArray {
78    /// Must be DataType::FixedSizeBinary(value_size)
79    data_type: DataType,
80    /// `len` values, each `value_size` bytes
81    value_data: Buffer,
82    /// Optional Null Buffer
83    nulls: Option<NullBuffer>,
84    /// Number of elements in the array
85    len: usize,
86    /// size of each element, validated to fit in a positive i32
87    ///
88    /// Corresponds to the [`byteWidth` field] in the Arrow Spec
89    ///
90    /// note: Arrow stores `value_len` using i32. This implementation stores it
91    /// as a usize to ensure correct offset calculations.
92    ///
93    /// [`byteWidth` field]: https://github.com/apache/arrow/blob/2a89d03bbefd620b42126b8e00f8ae57e99cd638/format/Schema.fbs#L211
94    value_size: usize,
95}
96
97impl FixedSizeBinaryArray {
98    /// Create a new [`FixedSizeBinaryArray`] with `value_length` bytes per element, panicking on
99    /// failure
100    ///
101    /// # Panics
102    ///
103    /// Panics if [`Self::try_new`] returns an error
104    pub fn new(value_length: i32, values: Buffer, nulls: Option<NullBuffer>) -> Self {
105        Self::try_new(value_length, values, nulls).unwrap()
106    }
107
108    /// Create a new [`FixedSizeBinaryArray`] from the provided parts without validation.
109    ///
110    /// # Safety
111    /// - `value_length >= 0`
112    /// - `values.len() == len * value_length as usize`
113    /// - `nulls.len() == len` if `nulls` is `Some`
114    pub unsafe fn new_unchecked(
115        value_length: i32,
116        values: Buffer,
117        nulls: Option<NullBuffer>,
118        len: usize,
119    ) -> Self {
120        if cfg!(feature = "force_validate") {
121            return Self::try_new_with_len(value_length, values, nulls, len).unwrap();
122        }
123        Self {
124            data_type: DataType::FixedSizeBinary(value_length),
125            value_data: values,
126            value_size: value_length as usize,
127            nulls,
128            len,
129        }
130    }
131
132    /// Create a new [`Scalar`] from `value`
133    ///
134    /// # Panics
135    /// Panics if `value.as_ref().len() > i32::MAX`
136    pub fn new_scalar(value: impl AsRef<[u8]>) -> Scalar<Self> {
137        let v = value.as_ref();
138        let value_length =
139            i32::try_from(v.len()).expect("FixedSizeBinaryArray value length exceeds i32");
140        Scalar::new(Self::new(value_length, Buffer::from(v), None))
141    }
142
143    /// Create a new [`FixedSizeBinaryArray`] from the provided parts, returning an error on failure
144    ///
145    /// Creating an array with `value_length == 0` will try to get the length from the null
146    /// buffer. If no null buffer is provided, the resulting array will have length zero.
147    /// You can use [`Self::try_new_with_len`] to provide the length
148    ///
149    /// # Errors
150    ///
151    /// * `value_length < 0`
152    /// * `values.len() / value_length != nulls.len()`
153    /// * `value_length == 0 && values.len() != 0`
154    pub fn try_new(
155        value_length: i32,
156        values: Buffer,
157        nulls: Option<NullBuffer>,
158    ) -> Result<Self, ArrowError> {
159        let value_size = value_length.to_usize().ok_or_else(|| {
160            ArrowError::InvalidArgumentError(format!(
161                "Value length cannot be negative, got {value_length}"
162            ))
163        })?;
164
165        let len = match values.len().checked_div(value_size) {
166            Some(len) => {
167                if let Some(n) = nulls.as_ref()
168                    && n.len() != len
169                {
170                    return Err(ArrowError::InvalidArgumentError(format!(
171                        "Incorrect length of null buffer for FixedSizeBinaryArray, expected {} got {}",
172                        len,
173                        n.len(),
174                    )));
175                }
176
177                len
178            }
179            None => {
180                if !values.is_empty() {
181                    return Err(ArrowError::InvalidArgumentError(
182                        "Buffer cannot have non-zero length if the value length is zero".to_owned(),
183                    ));
184                }
185
186                // If the value length is zero, try to determine the length from the null buffer
187                nulls.as_ref().map(|n| n.len()).unwrap_or(0)
188            }
189        };
190
191        Self::try_new_with_len(value_length, values, nulls, len)
192    }
193
194    /// Create a new [`FixedSizeBinaryArray`] from the provided parts and number of elements, returning an error on failure
195    ///
196    /// This is useful when the length cannot be determined from the provided values (in case of `value_length == 0`) or nulls (`nulls.is_none()`).
197    ///
198    /// # Errors
199    ///
200    /// * `value_length < 0`
201    /// * `values.len() / value_length != len`
202    /// * `value_length == 0 && values.len() != 0`
203    /// * `nulls.len() != len`
204    /// * `value_length != 0 && values.len() / value_length != len`
205    pub fn try_new_with_len(
206        value_length: i32,
207        values: Buffer,
208        nulls: Option<NullBuffer>,
209        len: usize,
210    ) -> Result<Self, ArrowError> {
211        let data_type = DataType::FixedSizeBinary(value_length);
212        let value_size = value_length.to_usize().ok_or_else(|| {
213            ArrowError::InvalidArgumentError(format!(
214                "Value length cannot be negative, got {value_length}"
215            ))
216        })?;
217
218        if let Some(nulls) = &nulls
219            && nulls.len() != len
220        {
221            return Err(ArrowError::InvalidArgumentError(format!(
222                "Incorrect length of null buffer for FixedSizeBinaryArray, expected {} got {}",
223                len,
224                nulls.len(),
225            )));
226        }
227
228        if value_size != 0 && values.len() / value_size != len {
229            return Err(ArrowError::InvalidArgumentError(format!(
230                "Incorrect length of values buffer for FixedSizeBinaryArray, expected {} got {}",
231                len,
232                values.len() / value_size,
233            )));
234        }
235
236        if value_size == 0 && !values.is_empty() {
237            return Err(ArrowError::InvalidArgumentError(
238                "Buffer cannot have non-zero length if the value length is zero".to_owned(),
239            ));
240        }
241
242        Ok(Self {
243            data_type,
244            value_data: values,
245            value_size,
246            nulls,
247            len,
248        })
249    }
250
251    /// Create a new [`FixedSizeBinaryArray`] of length `len` where all values are null
252    ///
253    /// # Panics
254    ///
255    /// Panics if
256    ///
257    /// * `value_length < 0`
258    /// * `value_length * len` would overflow `usize`
259    /// * `value_length * len * 8` would overflow `usize`
260    pub fn new_null(value_length: i32, len: usize) -> Self {
261        const BITS_IN_A_BYTE: usize = 8;
262        let value_size = value_length.to_usize().unwrap();
263        let capacity_in_bytes = value_size.checked_mul(len).unwrap();
264        let capacity_in_bits = capacity_in_bytes.checked_mul(BITS_IN_A_BYTE).unwrap();
265        Self {
266            data_type: DataType::FixedSizeBinary(value_length),
267            value_data: MutableBuffer::new_null(capacity_in_bits).into(),
268            nulls: Some(NullBuffer::new_null(len)),
269            value_size,
270            len,
271        }
272    }
273
274    /// Deconstruct this array into its constituent parts
275    pub fn into_parts(self) -> (i32, Buffer, Option<NullBuffer>) {
276        let value_length = self.value_length();
277        (value_length, self.value_data, self.nulls)
278    }
279
280    /// Returns the element at index `i` as a byte slice.
281    ///
282    /// Note: This method does not check for nulls and the value is arbitrary
283    /// (but still well-defined) if [`is_null`](Self::is_null) returns true for the index.
284    ///
285    /// # Panics
286    /// Panics if index `i` is out of bounds.
287    pub fn value(&self, i: usize) -> &[u8] {
288        let len = self.len();
289        assert!(
290            i < len,
291            "Trying to access an element at index {i} from a FixedSizeBinaryArray of length {len}",
292        );
293        let position = i * self.value_size;
294        unsafe {
295            std::slice::from_raw_parts(self.value_data.as_ptr().add(position), self.value_size)
296        }
297    }
298
299    /// Returns the element at index `i` as a byte slice.
300    ///
301    /// Note: This method does not check for nulls and the value is arbitrary
302    /// if [`is_null`](Self::is_null) returns true for the index.
303    ///
304    /// # Safety
305    ///
306    /// Caller is responsible for ensuring that the index is within the bounds
307    /// of the array
308    pub unsafe fn value_unchecked(&self, i: usize) -> &[u8] {
309        let position = i * self.value_size;
310        unsafe {
311            std::slice::from_raw_parts(self.value_data.as_ptr().add(position), self.value_size)
312        }
313    }
314
315    /// Returns the offset for the element at index `i`.
316    ///
317    /// Note this doesn't do any bound checking, for performance reason.
318    ///
319    /// # Panics
320    ///
321    /// Panics if the computed byte offset exceeds `i32::MAX`.
322    #[deprecated(since = "59.0.0", note = "Use i * value_size() instead")]
323    #[inline]
324    pub fn value_offset(&self, i: usize) -> i32 {
325        self.value_length() * i as i32
326    }
327
328    /// Returns the length for an element.
329    ///
330    /// All elements have the same length as the array is a fixed size.
331    ///
332    /// Returns an `i32` to be compatible with the Arrow spec.
333    ///
334    /// Use [`Self::value_size`] to return a `usize`.
335    #[inline]
336    pub fn value_length(&self) -> i32 {
337        // This is safe: constructor validated that value_size was a valid i32
338        self.value_size as i32
339    }
340
341    /// Return the length for an element, as a usize.
342    ///
343    /// All elements have the same length as the array is a fixed size.
344    ///
345    /// Note: This value will always fit, without overflow, into an i32
346    #[inline]
347    pub fn value_size(&self) -> usize {
348        self.value_size
349    }
350
351    /// Returns the values of this array.
352    ///
353    /// Unlike [`Self::value_data`] this returns the [`Buffer`]
354    /// allowing for zero-copy cloning.
355    #[inline]
356    pub fn values(&self) -> &Buffer {
357        &self.value_data
358    }
359
360    /// Returns the raw value data.
361    pub fn value_data(&self) -> &[u8] {
362        self.value_data.as_slice()
363    }
364
365    /// Returns a zero-copy slice of this array with the indicated offset and length.
366    ///
367    /// # Panics
368    /// Panics if `offset + len > self.len()`
369    pub fn slice(&self, offset: usize, len: usize) -> Self {
370        assert!(
371            offset.saturating_add(len) <= self.len,
372            "the length + offset of the sliced FixedSizeBinaryArray cannot exceed the existing length"
373        );
374        let offset_bytes = offset
375            .checked_mul(self.value_size)
376            .expect("offset overflow");
377        let len_bytes = len.checked_mul(self.value_size).expect("offset overflow");
378
379        Self {
380            data_type: self.data_type.clone(),
381            nulls: self.nulls.as_ref().map(|n| n.slice(offset, len)),
382            value_size: self.value_size,
383            value_data: self.value_data.slice_with_length(offset_bytes, len_bytes),
384            len,
385        }
386    }
387
388    /// Create an array from an iterable argument of sparse byte slices.
389    /// Sparsity means that items returned by the iterator are optional, i.e input argument can
390    /// contain `None` items.
391    ///
392    /// # Examples
393    ///
394    /// ```
395    /// use arrow_array::FixedSizeBinaryArray;
396    /// let input_arg = vec![
397    ///     None,
398    ///     Some(vec![7, 8]),
399    ///     Some(vec![9, 10]),
400    ///     None,
401    ///     Some(vec![13, 14]),
402    ///     None,
403    /// ];
404    /// let array = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.into_iter()).unwrap();
405    /// ```
406    ///
407    /// # Errors
408    ///
409    /// Returns error if argument has length zero, or sizes of nested slices don't match.
410    #[deprecated(
411        since = "28.0.0",
412        note = "This function will fail if the iterator produces only None values; prefer `try_from_sparse_iter_with_size`"
413    )]
414    pub fn try_from_sparse_iter<T, U>(mut iter: T) -> Result<Self, ArrowError>
415    where
416        T: Iterator<Item = Option<U>>,
417        U: AsRef<[u8]>,
418    {
419        let mut len = 0;
420        let mut value_size = None;
421        let mut byte = 0;
422
423        let iter_size_hint = iter.size_hint().0;
424        let mut null_buf = MutableBuffer::new(bit_util::ceil(iter_size_hint, 8));
425        let mut buffer = MutableBuffer::new(0);
426
427        let mut prepend = 0;
428        iter.try_for_each(|item| -> Result<(), ArrowError> {
429            // extend null bitmask by one byte per each 8 items
430            if byte == 0 {
431                null_buf.push(0u8);
432                byte = 8;
433            }
434            byte -= 1;
435
436            if let Some(slice) = item {
437                let slice = slice.as_ref();
438                if let Some(size) = value_size {
439                    if size != slice.len() {
440                        return Err(ArrowError::InvalidArgumentError(format!(
441                            "Nested array size mismatch: one is {}, and the other is {}",
442                            size,
443                            slice.len()
444                        )));
445                    }
446                } else {
447                    let len = slice.len();
448                    value_size = Some(len);
449                    // Now that we know how large each element is we can reserve
450                    // sufficient capacity in the underlying mutable buffer for
451                    // the data.
452                    if let Some(capacity) = iter_size_hint.checked_mul(len) {
453                        buffer
454                            .try_reserve(capacity)
455                            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
456                    }
457                    let prepend_zeros = slice.len().checked_mul(prepend).ok_or_else(|| {
458                        ArrowError::InvalidArgumentError(format!(
459                            "FixedSizeBinaryArray error: value size {} * prepend {prepend} exceeds usize",
460                            slice.len()
461                        ))
462                    })?;
463                    buffer
464                        .try_extend_zeros(prepend_zeros)
465                        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
466                }
467                bit_util::set_bit(null_buf.as_slice_mut(), len);
468                buffer
469                    .try_extend_from_slice(slice)
470                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
471            } else if let Some(size) = value_size {
472                buffer
473                    .try_extend_zeros(size)
474                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
475            } else {
476                prepend += 1;
477            }
478
479            len += 1;
480
481            Ok(())
482        })?;
483
484        if len == 0 {
485            return Err(ArrowError::InvalidArgumentError(
486                "Input iterable argument has no data".to_owned(),
487            ));
488        }
489
490        let nulls = NullBuffer::from_unsliced_buffer(null_buf, len);
491
492        let value_size = value_size.unwrap_or(0);
493        let value_length = value_size.try_into().map_err(|_| {
494            ArrowError::InvalidArgumentError(format!(
495                "FixedSizeBinaryArray value length exceeds i32, got {value_size}"
496            ))
497        })?;
498        Ok(Self {
499            data_type: DataType::FixedSizeBinary(value_length),
500            value_data: buffer.into(),
501            nulls,
502            value_size,
503            len,
504        })
505    }
506
507    /// Create an array from an iterable argument of sparse byte slices.
508    /// Sparsity means that items returned by the iterator are optional, i.e input argument can
509    /// contain `None` items. In cases where the iterator returns only `None` values, this
510    /// also takes a `value_length` parameter to ensure that a valid
511    /// [`FixedSizeBinaryArray`] is still created.
512    ///
513    /// # Examples
514    ///
515    /// ```
516    /// use arrow_array::FixedSizeBinaryArray;
517    /// let input_arg = vec![
518    ///     None,
519    ///     Some(vec![7, 8]),
520    ///     Some(vec![9, 10]),
521    ///     None,
522    ///     Some(vec![13, 14]),
523    ///     None,
524    /// ];
525    /// let array = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
526    /// ```
527    ///
528    /// # Errors
529    ///
530    /// - `value_length` is negative
531    /// - A byte slice has a different length
532    /// - Size arithmetic overflows
533    /// - Buffer allocation fails
534    pub fn try_from_sparse_iter_with_size<T, U>(
535        mut iter: T,
536        value_length: i32,
537    ) -> Result<Self, ArrowError>
538    where
539        T: Iterator<Item = Option<U>>,
540        U: AsRef<[u8]>,
541    {
542        let value_size = value_length.to_usize().ok_or_else(|| {
543            ArrowError::InvalidArgumentError(format!(
544                "Value length cannot be negative, got {value_length}"
545            ))
546        })?;
547        let mut len = 0;
548        let mut byte = 0;
549
550        let iter_size_hint = iter.size_hint().0;
551        let mut null_buf = MutableBuffer::try_with_capacity(bit_util::ceil(iter_size_hint, 8))
552            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
553        let capacity = iter_size_hint.checked_mul(value_size).ok_or_else(|| {
554            ArrowError::InvalidArgumentError(format!(
555                "FixedSizeBinaryArray error: value size {value_size} * len hint {iter_size_hint} exceeds usize"
556            ))
557        })?;
558        let mut buffer = MutableBuffer::try_with_capacity(capacity)
559            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
560
561        iter.try_for_each(|item| -> Result<(), ArrowError> {
562            // extend null bitmask by one byte per each 8 items
563            if byte == 0 {
564                null_buf
565                    .try_extend_from_slice(&[0u8])
566                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
567                byte = 8;
568            }
569            byte -= 1;
570
571            if let Some(slice) = item {
572                let slice = slice.as_ref();
573                if value_size != slice.len() {
574                    return Err(ArrowError::InvalidArgumentError(format!(
575                        "Nested array size mismatch: one is {}, and the other is {}",
576                        value_length,
577                        slice.len()
578                    )));
579                }
580
581                bit_util::set_bit(null_buf.as_slice_mut(), len);
582                buffer
583                    .try_extend_from_slice(slice)
584                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
585            } else {
586                buffer
587                    .try_extend_zeros(value_size)
588                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
589            }
590
591            len += 1;
592
593            Ok(())
594        })?;
595
596        let nulls = NullBuffer::from_unsliced_buffer(null_buf, len);
597
598        Ok(Self {
599            data_type: DataType::FixedSizeBinary(value_length),
600            value_data: buffer.into(),
601            nulls,
602            len,
603            value_size,
604        })
605    }
606
607    /// Create an array from an iterable argument of byte slices.
608    ///
609    /// # Examples
610    ///
611    /// ```
612    /// use arrow_array::FixedSizeBinaryArray;
613    /// let input_arg = vec![
614    ///     vec![1, 2],
615    ///     vec![3, 4],
616    ///     vec![5, 6],
617    /// ];
618    /// let array = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
619    /// ```
620    ///
621    /// # Errors
622    ///
623    /// - The iterator is empty
624    /// - The byte slices have different lengths
625    /// - The value length exceeds `i32`
626    /// - Buffer allocation fails
627    pub fn try_from_iter<T, U>(mut iter: T) -> Result<Self, ArrowError>
628    where
629        T: Iterator<Item = U>,
630        U: AsRef<[u8]>,
631    {
632        let mut len = 0;
633        let mut value_size = None;
634        let iter_size_hint = iter.size_hint().0;
635        let mut buffer = MutableBuffer::default();
636
637        iter.try_for_each(|item| -> Result<(), ArrowError> {
638            let slice = item.as_ref();
639            if let Some(value_size) = value_size {
640                if value_size != slice.len() {
641                    return Err(ArrowError::InvalidArgumentError(format!(
642                        "Nested array size mismatch: one is {value_size}, and the other is {}",
643                        slice.len()
644                    )));
645                }
646            } else {
647                let len = slice.len();
648                value_size = Some(len);
649                if let Some(capacity) = iter_size_hint.checked_mul(len) {
650                    buffer
651                        .try_reserve(capacity)
652                        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
653                }
654            }
655
656            buffer
657                .try_extend_from_slice(slice)
658                .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
659
660            len += 1;
661
662            Ok(())
663        })?;
664
665        if len == 0 {
666            return Err(ArrowError::InvalidArgumentError(
667                "Input iterable argument has no data".to_owned(),
668            ));
669        }
670
671        let value_size = value_size.unwrap_or(0);
672        let value_length = value_size.try_into().map_err(|_| {
673            ArrowError::InvalidArgumentError(format!(
674                "FixedSizeBinaryArray value length exceeds i32, got {value_size}"
675            ))
676        })?;
677        Ok(Self {
678            data_type: DataType::FixedSizeBinary(value_length),
679            value_data: buffer.into(),
680            nulls: None,
681            value_size,
682            len,
683        })
684    }
685
686    /// constructs a new iterator
687    pub fn iter(&self) -> FixedSizeBinaryIter<'_> {
688        FixedSizeBinaryIter::new(self)
689    }
690}
691
692impl From<ArrayData> for FixedSizeBinaryArray {
693    fn from(data: ArrayData) -> Self {
694        let (data_type, len, nulls, offset, buffers, _child_data) = data.into_parts();
695
696        assert_eq!(
697            buffers.len(),
698            1,
699            "FixedSizeBinaryArray data should contain 1 buffer only (values)"
700        );
701        let DataType::FixedSizeBinary(value_length) = data_type else {
702            panic!("Expected data type to be FixedSizeBinary")
703        };
704
705        let value_size = value_length
706            .to_usize()
707            .expect("FixedSizeBinaryArray value length must be non-negative");
708        let value_data = buffers[0].slice_with_length(
709            offset.checked_mul(value_size).expect("offset overflow"),
710            len.checked_mul(value_size).expect("length overflow"),
711        );
712
713        Self {
714            data_type,
715            value_data,
716            nulls,
717            len,
718            value_size,
719        }
720    }
721}
722
723impl From<FixedSizeBinaryArray> for ArrayData {
724    fn from(array: FixedSizeBinaryArray) -> Self {
725        let builder = ArrayDataBuilder::new(array.data_type)
726            .len(array.len)
727            .buffers(vec![array.value_data])
728            .nulls(array.nulls);
729
730        unsafe { builder.build_unchecked() }
731    }
732}
733
734/// Creates a `FixedSizeBinaryArray` from `FixedSizeList<u8>` array
735impl From<FixedSizeListArray> for FixedSizeBinaryArray {
736    fn from(v: FixedSizeListArray) -> Self {
737        let value_len = v.value_length();
738        let v = v.into_data();
739        assert_eq!(
740            v.child_data().len(),
741            1,
742            "FixedSizeBinaryArray can only be created from list array of u8 values \
743             (i.e. FixedSizeList<PrimitiveArray<u8>>)."
744        );
745        let child_data = &v.child_data()[0];
746
747        assert_eq!(
748            child_data.child_data().len(),
749            0,
750            "FixedSizeBinaryArray can only be created from list array of u8 values \
751             (i.e. FixedSizeList<PrimitiveArray<u8>>)."
752        );
753        assert_eq!(
754            child_data.data_type(),
755            &DataType::UInt8,
756            "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays, mismatched data types."
757        );
758        assert_eq!(
759            child_data.null_count(),
760            0,
761            "The child array cannot contain null values."
762        );
763
764        let builder = ArrayData::builder(DataType::FixedSizeBinary(value_len))
765            .len(v.len())
766            .offset(v.offset())
767            .add_buffer(child_data.buffers()[0].slice(child_data.offset()))
768            .nulls(v.nulls().cloned());
769
770        let data = unsafe { builder.build_unchecked() };
771        Self::from(data)
772    }
773}
774
775impl TryFrom<Vec<Option<&[u8]>>> for FixedSizeBinaryArray {
776    type Error = ArrowError;
777
778    fn try_from(v: Vec<Option<&[u8]>>) -> Result<Self, Self::Error> {
779        #[expect(deprecated)]
780        Self::try_from_sparse_iter(v.into_iter())
781    }
782}
783
784impl TryFrom<Vec<&[u8]>> for FixedSizeBinaryArray {
785    type Error = ArrowError;
786
787    fn try_from(v: Vec<&[u8]>) -> Result<Self, Self::Error> {
788        Self::try_from_iter(v.into_iter())
789    }
790}
791
792impl<const N: usize> TryFrom<Vec<Option<&[u8; N]>>> for FixedSizeBinaryArray {
793    type Error = ArrowError;
794
795    fn try_from(v: Vec<Option<&[u8; N]>>) -> Result<Self, Self::Error> {
796        let size = N.try_into().map_err(|_| {
797            ArrowError::InvalidArgumentError(format!(
798                "FixedSizeBinaryArray value length exceeds i32, got {N}"
799            ))
800        })?;
801        Self::try_from_sparse_iter_with_size(v.into_iter(), size)
802    }
803}
804
805impl<const N: usize> TryFrom<Vec<&[u8; N]>> for FixedSizeBinaryArray {
806    type Error = ArrowError;
807
808    fn try_from(v: Vec<&[u8; N]>) -> Result<Self, Self::Error> {
809        Self::try_from_iter(v.into_iter())
810    }
811}
812
813impl std::fmt::Debug for FixedSizeBinaryArray {
814    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
815        write!(f, "FixedSizeBinaryArray<{}>\n[\n", self.value_length())?;
816        print_long_array(self, f, &mut |index, f| {
817            std::fmt::Debug::fmt(&self.value(index), f)
818        })?;
819        write!(f, "]")
820    }
821}
822
823/// SAFETY: Correctly implements the contract of Arrow Arrays
824unsafe impl Array for FixedSizeBinaryArray {
825    fn as_any(&self) -> &dyn Any {
826        self
827    }
828
829    fn to_data(&self) -> ArrayData {
830        self.clone().into()
831    }
832
833    fn into_data(self) -> ArrayData {
834        self.into()
835    }
836
837    fn data_type(&self) -> &DataType {
838        &self.data_type
839    }
840
841    fn slice(&self, offset: usize, length: usize) -> ArrayRef {
842        Arc::new(self.slice(offset, length))
843    }
844
845    fn len(&self) -> usize {
846        self.len
847    }
848
849    fn is_empty(&self) -> bool {
850        self.len == 0
851    }
852
853    fn shrink_to_fit(&mut self) {
854        self.value_data.shrink_to_fit();
855        if let Some(nulls) = &mut self.nulls {
856            nulls.shrink_to_fit();
857        }
858    }
859
860    fn offset(&self) -> usize {
861        // Slices are normalized by slicing `value_data`/`nulls` directly;
862        // FSB does not retain a separate logical element offset.
863        0
864    }
865
866    fn nulls(&self) -> Option<&NullBuffer> {
867        self.nulls.as_ref()
868    }
869
870    fn logical_null_count(&self) -> usize {
871        // More efficient that the default implementation
872        self.null_count()
873    }
874
875    fn get_buffer_memory_size(&self) -> usize {
876        let mut sum = self.value_data.capacity();
877        if let Some(n) = &self.nulls {
878            sum += n.buffer().capacity();
879        }
880        sum
881    }
882
883    fn get_array_memory_size(&self) -> usize {
884        std::mem::size_of::<Self>() + self.get_buffer_memory_size()
885    }
886
887    #[cfg(feature = "pool")]
888    fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
889        self.value_data.claim(pool);
890        if let Some(nulls) = &self.nulls {
891            nulls.claim(pool);
892        }
893    }
894}
895
896impl<'a> ArrayAccessor for &'a FixedSizeBinaryArray {
897    type Item = &'a [u8];
898
899    fn value(&self, index: usize) -> Self::Item {
900        FixedSizeBinaryArray::value(self, index)
901    }
902
903    unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
904        unsafe { FixedSizeBinaryArray::value_unchecked(self, index) }
905    }
906}
907
908impl<'a> IntoIterator for &'a FixedSizeBinaryArray {
909    type Item = Option<&'a [u8]>;
910    type IntoIter = FixedSizeBinaryIter<'a>;
911
912    fn into_iter(self) -> Self::IntoIter {
913        FixedSizeBinaryIter::<'a>::new(self)
914    }
915}
916
917#[cfg(test)]
918mod tests {
919    use super::*;
920    use crate::RecordBatch;
921    use arrow_schema::{Field, Schema};
922
923    #[test]
924    fn test_fixed_size_binary_array() {
925        let values = b"hellotherearrow";
926
927        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
928            .len(3)
929            .add_buffer(Buffer::from(values))
930            .build()
931            .unwrap();
932        let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
933        assert_eq!(3, fixed_size_binary_array.len());
934        assert_eq!(0, fixed_size_binary_array.null_count());
935        assert_eq!(
936            [b'h', b'e', b'l', b'l', b'o'],
937            fixed_size_binary_array.value(0)
938        );
939        assert_eq!(
940            [b't', b'h', b'e', b'r', b'e'],
941            fixed_size_binary_array.value(1)
942        );
943        assert_eq!(
944            [b'a', b'r', b'r', b'o', b'w'],
945            fixed_size_binary_array.value(2)
946        );
947        assert_eq!(5, fixed_size_binary_array.value_length());
948        for i in 0..3 {
949            assert!(fixed_size_binary_array.is_valid(i));
950            assert!(!fixed_size_binary_array.is_null(i));
951        }
952
953        // Test binary array with offset
954        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
955            .len(2)
956            .offset(1)
957            .add_buffer(Buffer::from(values))
958            .build()
959            .unwrap();
960        let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
961        assert_eq!(
962            [b't', b'h', b'e', b'r', b'e'],
963            fixed_size_binary_array.value(0)
964        );
965        assert_eq!(
966            [b'a', b'r', b'r', b'o', b'w'],
967            fixed_size_binary_array.value(1)
968        );
969        assert_eq!(2, fixed_size_binary_array.len());
970        assert_eq!(5, fixed_size_binary_array.value_length());
971    }
972
973    #[test]
974    fn test_fixed_size_binary_array_from_fixed_size_list_array() {
975        let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
976        let values_data = ArrayData::builder(DataType::UInt8)
977            .len(12)
978            .offset(2)
979            .add_buffer(Buffer::from_slice_ref(values))
980            .build()
981            .unwrap();
982        // [null, [10, 11, 12, 13]]
983        let array_data = unsafe {
984            ArrayData::builder(DataType::FixedSizeList(
985                Arc::new(Field::new_list_field(DataType::UInt8, false)),
986                4,
987            ))
988            .len(2)
989            .offset(1)
990            .add_child_data(values_data)
991            .null_bit_buffer(Some(Buffer::from_slice_ref([0b101])))
992            .build_unchecked()
993        };
994        let list_array = FixedSizeListArray::from(array_data);
995        let binary_array = FixedSizeBinaryArray::from(list_array);
996
997        assert_eq!(2, binary_array.len());
998        assert_eq!(1, binary_array.null_count());
999        assert!(binary_array.is_null(0));
1000        assert!(binary_array.is_valid(1));
1001        assert_eq!(&[10, 11, 12, 13], binary_array.value(1));
1002    }
1003
1004    #[test]
1005    #[should_panic(
1006        expected = "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays"
1007    )]
1008    // Different error messages, so skip for now
1009    // https://github.com/apache/arrow-rs/issues/1545
1010    #[cfg(not(feature = "force_validate"))]
1011    fn test_fixed_size_binary_array_from_incorrect_fixed_size_list_array() {
1012        let values: [u32; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
1013        let values_data = ArrayData::builder(DataType::UInt32)
1014            .len(12)
1015            .add_buffer(Buffer::from_slice_ref(values))
1016            .build()
1017            .unwrap();
1018
1019        let array_data = unsafe {
1020            ArrayData::builder(DataType::FixedSizeList(
1021                Arc::new(Field::new_list_field(DataType::Binary, false)),
1022                4,
1023            ))
1024            .len(3)
1025            .add_child_data(values_data)
1026            .build_unchecked()
1027        };
1028        let list_array = FixedSizeListArray::from(array_data);
1029        drop(FixedSizeBinaryArray::from(list_array));
1030    }
1031
1032    #[test]
1033    // Under force_validate `build_unchecked` panics on the invalid child data
1034    // before we reach the `FixedSizeBinaryArray::from` path we want to test.
1035    #[cfg(not(feature = "force_validate"))]
1036    #[should_panic(expected = "The child array cannot contain null values.")]
1037    fn test_fixed_size_binary_array_from_fixed_size_list_array_with_child_nulls_failed() {
1038        let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
1039        let values_data = ArrayData::builder(DataType::UInt8)
1040            .len(12)
1041            .add_buffer(Buffer::from_slice_ref(values))
1042            .null_bit_buffer(Some(Buffer::from_slice_ref([0b101010101010])))
1043            .build()
1044            .unwrap();
1045
1046        let array_data = unsafe {
1047            ArrayData::builder(DataType::FixedSizeList(
1048                Arc::new(Field::new_list_field(DataType::UInt8, false)),
1049                4,
1050            ))
1051            .len(3)
1052            .add_child_data(values_data)
1053            .build_unchecked()
1054        };
1055        let list_array = FixedSizeListArray::from(array_data);
1056        drop(FixedSizeBinaryArray::from(list_array));
1057    }
1058
1059    #[test]
1060    fn test_fixed_size_binary_array_fmt_debug() {
1061        let values = b"hellotherearrow";
1062
1063        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
1064            .len(3)
1065            .add_buffer(Buffer::from(values))
1066            .build()
1067            .unwrap();
1068        let arr = FixedSizeBinaryArray::from(array_data);
1069        assert_eq!(
1070            "FixedSizeBinaryArray<5>\n[\n  [104, 101, 108, 108, 111],\n  [116, 104, 101, 114, 101],\n  [97, 114, 114, 111, 119],\n]",
1071            format!("{arr:?}")
1072        );
1073    }
1074
1075    #[test]
1076    fn test_fixed_size_binary_array_from_iter() {
1077        let input_arg = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
1078        let arr = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
1079
1080        assert_eq!(2, arr.value_length());
1081        assert_eq!(3, arr.len())
1082    }
1083
1084    #[test]
1085    fn test_all_none_fixed_size_binary_array_from_sparse_iter() {
1086        let none_option: Option<[u8; 32]> = None;
1087        let input_arg = vec![none_option, none_option, none_option];
1088        #[expect(deprecated)]
1089        let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.into_iter()).unwrap();
1090        assert_eq!(0, arr.value_length());
1091        assert_eq!(3, arr.len())
1092    }
1093
1094    #[test]
1095    fn test_fixed_size_binary_array_from_sparse_iter() {
1096        let input_arg = vec![
1097            None,
1098            Some(vec![7, 8]),
1099            Some(vec![9, 10]),
1100            None,
1101            Some(vec![13, 14]),
1102        ];
1103        #[expect(deprecated)]
1104        let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.iter().cloned()).unwrap();
1105        assert_eq!(2, arr.value_length());
1106        assert_eq!(5, arr.len());
1107
1108        let arr =
1109            FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
1110        assert_eq!(2, arr.value_length());
1111        assert_eq!(5, arr.len());
1112    }
1113
1114    #[test]
1115    fn test_fixed_size_binary_array_from_sparse_iter_with_size_all_none() {
1116        let input_arg = vec![None, None, None, None, None] as Vec<Option<Vec<u8>>>;
1117
1118        let arr = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 16)
1119            .unwrap();
1120        assert_eq!(16, arr.value_length());
1121        assert_eq!(5, arr.len())
1122    }
1123
1124    #[test]
1125    fn test_fixed_size_binary_array_from_vec() {
1126        let values = vec![b"one".as_slice(), b"two", b"six", b"ten"];
1127        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1128        assert_eq!(array.len(), 4);
1129        assert_eq!(array.null_count(), 0);
1130        assert_eq!(array.logical_null_count(), 0);
1131        assert_eq!(array.value(0), b"one");
1132        assert_eq!(array.value(1), b"two");
1133        assert_eq!(array.value(2), b"six");
1134        assert_eq!(array.value(3), b"ten");
1135        assert!(!array.is_null(0));
1136        assert!(!array.is_null(1));
1137        assert!(!array.is_null(2));
1138        assert!(!array.is_null(3));
1139    }
1140
1141    #[test]
1142    fn test_fixed_size_binary_array_from_vec_incorrect_length() {
1143        let values = vec![b"one".as_slice(), b"two", b"three", b"four"];
1144        assert!(FixedSizeBinaryArray::try_from(values).is_err());
1145    }
1146
1147    #[test]
1148    fn test_fixed_size_binary_array_from_opt_vec() {
1149        let values = vec![
1150            Some(b"one".as_slice()),
1151            Some(b"two"),
1152            None,
1153            Some(b"six"),
1154            Some(b"ten"),
1155        ];
1156        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1157        assert_eq!(array.len(), 5);
1158        assert_eq!(array.value(0), b"one");
1159        assert_eq!(array.value(1), b"two");
1160        assert_eq!(array.value(3), b"six");
1161        assert_eq!(array.value(4), b"ten");
1162        assert!(!array.is_null(0));
1163        assert!(!array.is_null(1));
1164        assert!(array.is_null(2));
1165        assert!(!array.is_null(3));
1166        assert!(!array.is_null(4));
1167    }
1168
1169    #[test]
1170    fn test_fixed_size_binary_array_from_opt_vec_incorrect_length() {
1171        let values = vec![
1172            Some(b"one".as_slice()),
1173            Some(b"two"),
1174            None,
1175            Some(b"three"),
1176            Some(b"four"),
1177        ];
1178        assert!(FixedSizeBinaryArray::try_from(values).is_err());
1179    }
1180
1181    #[test]
1182    fn fixed_size_binary_array_all_null() {
1183        let data = vec![None] as Vec<Option<String>>;
1184        let array =
1185            FixedSizeBinaryArray::try_from_sparse_iter_with_size(data.into_iter(), 0).unwrap();
1186        array
1187            .into_data()
1188            .validate_full()
1189            .expect("All null array has valid array data");
1190    }
1191
1192    #[test]
1193    // Test for https://github.com/apache/arrow-rs/issues/1390
1194    fn fixed_size_binary_array_all_null_in_batch_with_schema() {
1195        let schema = Schema::new(vec![Field::new("a", DataType::FixedSizeBinary(2), true)]);
1196
1197        let none_option: Option<[u8; 2]> = None;
1198        let item = FixedSizeBinaryArray::try_from_sparse_iter_with_size(
1199            vec![none_option, none_option, none_option].into_iter(),
1200            2,
1201        )
1202        .unwrap();
1203
1204        // Should not panic
1205        RecordBatch::try_new(Arc::new(schema), vec![Arc::new(item)]).unwrap();
1206    }
1207
1208    #[test]
1209    #[should_panic(
1210        expected = "Trying to access an element at index 4 from a FixedSizeBinaryArray of length 3"
1211    )]
1212    fn test_fixed_size_binary_array_get_value_index_out_of_bound() {
1213        let values = vec![Some(b"one".as_slice()), Some(b"two"), None];
1214        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1215
1216        array.value(4);
1217    }
1218
1219    #[test]
1220    fn test_constructors() {
1221        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1222        let a = FixedSizeBinaryArray::new(2, buffer.clone(), None);
1223        assert_eq!(a.len(), 5);
1224
1225        let nulls = NullBuffer::new_null(5);
1226        FixedSizeBinaryArray::new(2, buffer.clone(), Some(nulls));
1227
1228        let null_array = FixedSizeBinaryArray::new_null(4, 3);
1229        assert_eq!(null_array.len(), 3);
1230        assert_eq!(null_array.values().len(), 12);
1231
1232        let a = FixedSizeBinaryArray::new(3, buffer.clone(), None);
1233        assert_eq!(a.len(), 3);
1234
1235        let nulls = NullBuffer::new_null(3);
1236        FixedSizeBinaryArray::new(3, buffer.clone(), Some(nulls));
1237
1238        let err = FixedSizeBinaryArray::try_new(-1, buffer.clone(), None).unwrap_err();
1239
1240        assert_eq!(
1241            err.to_string(),
1242            "Invalid argument error: Value length cannot be negative, got -1"
1243        );
1244
1245        let nulls = NullBuffer::new_null(3);
1246        let err = FixedSizeBinaryArray::try_new(2, buffer.clone(), Some(nulls)).unwrap_err();
1247        assert_eq!(
1248            err.to_string(),
1249            "Invalid argument error: Incorrect length of null buffer for FixedSizeBinaryArray, expected 5 got 3"
1250        );
1251
1252        let zero_sized = FixedSizeBinaryArray::new(0, Buffer::default(), None);
1253        assert_eq!(zero_sized.len(), 0);
1254        assert_eq!(zero_sized.null_count(), 0);
1255        assert_eq!(zero_sized.values().len(), 0);
1256
1257        let nulls = NullBuffer::new_null(3);
1258        let zero_sized_with_nulls = FixedSizeBinaryArray::new(0, Buffer::default(), Some(nulls));
1259        assert_eq!(zero_sized_with_nulls.len(), 3);
1260        assert_eq!(zero_sized_with_nulls.null_count(), 3);
1261        assert_eq!(zero_sized_with_nulls.values().len(), 0);
1262
1263        let zero_sized_with_non_empty_buffer_err =
1264            FixedSizeBinaryArray::try_new(0, buffer, None).unwrap_err();
1265        assert_eq!(
1266            zero_sized_with_non_empty_buffer_err.to_string(),
1267            "Invalid argument error: Buffer cannot have non-zero length if the value length is zero"
1268        );
1269    }
1270
1271    #[test]
1272    fn test_try_new_with_len() {
1273        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1274
1275        let a = FixedSizeBinaryArray::try_new_with_len(2, buffer.clone(), None, 5).unwrap();
1276        assert_eq!(a.len(), 5);
1277
1278        let nulls = NullBuffer::new_null(5);
1279        let a = FixedSizeBinaryArray::try_new_with_len(2, buffer, Some(nulls), 5).unwrap();
1280        assert_eq!(a.len(), 5);
1281        assert_eq!(a.null_count(), 5);
1282
1283        let a = FixedSizeBinaryArray::try_new_with_len(2, Buffer::default(), None, 0).unwrap();
1284        assert_eq!(a.len(), 0);
1285    }
1286
1287    #[test]
1288    fn test_try_new_with_len_zero_width() {
1289        // Zero-width with no nulls: the case where the length cannot be inferred from the parts
1290        let a = FixedSizeBinaryArray::try_new_with_len(0, Buffer::default(), None, 5).unwrap();
1291        assert_eq!(a.len(), 5);
1292        assert_eq!(a.null_count(), 0);
1293        assert_eq!(a.values().len(), 0);
1294
1295        let nulls = NullBuffer::new_null(3);
1296        let a =
1297            FixedSizeBinaryArray::try_new_with_len(0, Buffer::default(), Some(nulls), 3).unwrap();
1298        assert_eq!(a.len(), 3);
1299        assert_eq!(a.null_count(), 3);
1300    }
1301
1302    #[test]
1303    fn test_try_new_with_len_negative_value_length() {
1304        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1305        let err = FixedSizeBinaryArray::try_new_with_len(-1, buffer, None, 5).unwrap_err();
1306        assert_eq!(
1307            err.to_string(),
1308            "Invalid argument error: Value length cannot be negative, got -1"
1309        );
1310    }
1311
1312    #[test]
1313    fn test_try_new_with_len_incorrect_null_buffer_length() {
1314        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1315        let nulls = NullBuffer::new_null(3);
1316        let err = FixedSizeBinaryArray::try_new_with_len(2, buffer, Some(nulls), 5).unwrap_err();
1317        assert_eq!(
1318            err.to_string(),
1319            "Invalid argument error: Incorrect length of null buffer for FixedSizeBinaryArray, expected 5 got 3"
1320        );
1321    }
1322
1323    #[test]
1324    fn test_try_new_with_len_incorrect_values_buffer_length() {
1325        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1326        let err = FixedSizeBinaryArray::try_new_with_len(2, buffer, None, 3).unwrap_err();
1327        assert_eq!(
1328            err.to_string(),
1329            "Invalid argument error: Incorrect length of values buffer for FixedSizeBinaryArray, expected 3 got 5"
1330        );
1331    }
1332
1333    #[test]
1334    fn test_try_new_with_len_zero_width_non_empty_buffer() {
1335        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1336        let err = FixedSizeBinaryArray::try_new_with_len(0, buffer, None, 5).unwrap_err();
1337        assert_eq!(
1338            err.to_string(),
1339            "Invalid argument error: Buffer cannot have non-zero length if the value length is zero"
1340        );
1341    }
1342}