Skip to main content

arrow_array/array/
fixed_size_binary_array.rs

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