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 determined 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 DataType::FixedSizeBinary(value_length) = data_type else {
701            panic!("Expected data type to be FixedSizeBinary")
702        };
703
704        let value_size = value_length
705            .to_usize()
706            .expect("FixedSizeBinaryArray value length must be non-negative");
707        let value_data = buffers[0].slice_with_length(
708            offset.checked_mul(value_size).expect("offset overflow"),
709            len.checked_mul(value_size).expect("length overflow"),
710        );
711
712        Self {
713            data_type,
714            value_data,
715            nulls,
716            len,
717            value_size,
718        }
719    }
720}
721
722impl From<FixedSizeBinaryArray> for ArrayData {
723    fn from(array: FixedSizeBinaryArray) -> Self {
724        let builder = ArrayDataBuilder::new(array.data_type)
725            .len(array.len)
726            .buffers(vec![array.value_data])
727            .nulls(array.nulls);
728
729        unsafe { builder.build_unchecked() }
730    }
731}
732
733/// Creates a `FixedSizeBinaryArray` from `FixedSizeList<u8>` array
734impl From<FixedSizeListArray> for FixedSizeBinaryArray {
735    fn from(v: FixedSizeListArray) -> Self {
736        let value_len = v.value_length();
737        let v = v.into_data();
738        assert_eq!(
739            v.child_data().len(),
740            1,
741            "FixedSizeBinaryArray can only be created from list array of u8 values \
742             (i.e. FixedSizeList<PrimitiveArray<u8>>)."
743        );
744        let child_data = &v.child_data()[0];
745
746        assert_eq!(
747            child_data.child_data().len(),
748            0,
749            "FixedSizeBinaryArray can only be created from list array of u8 values \
750             (i.e. FixedSizeList<PrimitiveArray<u8>>)."
751        );
752        assert_eq!(
753            child_data.data_type(),
754            &DataType::UInt8,
755            "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays, mismatched data types."
756        );
757        assert_eq!(
758            child_data.null_count(),
759            0,
760            "The child array cannot contain null values."
761        );
762
763        let builder = ArrayData::builder(DataType::FixedSizeBinary(value_len))
764            .len(v.len())
765            .offset(v.offset())
766            .add_buffer(child_data.buffers()[0].slice(child_data.offset()))
767            .nulls(v.nulls().cloned());
768
769        let data = unsafe { builder.build_unchecked() };
770        Self::from(data)
771    }
772}
773
774impl TryFrom<Vec<Option<&[u8]>>> for FixedSizeBinaryArray {
775    type Error = ArrowError;
776
777    fn try_from(v: Vec<Option<&[u8]>>) -> Result<Self, Self::Error> {
778        #[expect(deprecated)]
779        Self::try_from_sparse_iter(v.into_iter())
780    }
781}
782
783impl TryFrom<Vec<&[u8]>> for FixedSizeBinaryArray {
784    type Error = ArrowError;
785
786    fn try_from(v: Vec<&[u8]>) -> Result<Self, Self::Error> {
787        Self::try_from_iter(v.into_iter())
788    }
789}
790
791impl<const N: usize> TryFrom<Vec<Option<&[u8; N]>>> for FixedSizeBinaryArray {
792    type Error = ArrowError;
793
794    fn try_from(v: Vec<Option<&[u8; N]>>) -> Result<Self, Self::Error> {
795        let size = N.try_into().map_err(|_| {
796            ArrowError::InvalidArgumentError(format!(
797                "FixedSizeBinaryArray value length exceeds i32, got {N}"
798            ))
799        })?;
800        Self::try_from_sparse_iter_with_size(v.into_iter(), size)
801    }
802}
803
804impl<const N: usize> TryFrom<Vec<&[u8; N]>> for FixedSizeBinaryArray {
805    type Error = ArrowError;
806
807    fn try_from(v: Vec<&[u8; N]>) -> Result<Self, Self::Error> {
808        Self::try_from_iter(v.into_iter())
809    }
810}
811
812impl std::fmt::Debug for FixedSizeBinaryArray {
813    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
814        write!(f, "FixedSizeBinaryArray<{}>\n[\n", self.value_length())?;
815        print_long_array(self, f, &mut |index, f| {
816            std::fmt::Debug::fmt(&self.value(index), f)
817        })?;
818        write!(f, "]")
819    }
820}
821
822/// SAFETY: Correctly implements the contract of Arrow Arrays
823unsafe impl Array for FixedSizeBinaryArray {
824    fn as_any(&self) -> &dyn Any {
825        self
826    }
827
828    fn to_data(&self) -> ArrayData {
829        self.clone().into()
830    }
831
832    fn into_data(self) -> ArrayData {
833        self.into()
834    }
835
836    fn data_type(&self) -> &DataType {
837        &self.data_type
838    }
839
840    fn slice(&self, offset: usize, length: usize) -> ArrayRef {
841        Arc::new(self.slice(offset, length))
842    }
843
844    fn len(&self) -> usize {
845        self.len
846    }
847
848    fn is_empty(&self) -> bool {
849        self.len == 0
850    }
851
852    fn shrink_to_fit(&mut self) {
853        self.value_data.shrink_to_fit();
854        if let Some(nulls) = &mut self.nulls {
855            nulls.shrink_to_fit();
856        }
857    }
858
859    fn offset(&self) -> usize {
860        // Slices are normalized by slicing `value_data`/`nulls` directly;
861        // FSB does not retain a separate logical element offset.
862        0
863    }
864
865    fn nulls(&self) -> Option<&NullBuffer> {
866        self.nulls.as_ref()
867    }
868
869    fn logical_null_count(&self) -> usize {
870        // More efficient that the default implementation
871        self.null_count()
872    }
873
874    fn get_buffer_memory_size(&self) -> usize {
875        let mut sum = self.value_data.capacity();
876        if let Some(n) = &self.nulls {
877            sum += n.buffer().capacity();
878        }
879        sum
880    }
881
882    fn get_array_memory_size(&self) -> usize {
883        std::mem::size_of::<Self>() + self.get_buffer_memory_size()
884    }
885
886    #[cfg(feature = "pool")]
887    fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
888        self.value_data.claim(pool);
889        if let Some(nulls) = &self.nulls {
890            nulls.claim(pool);
891        }
892    }
893}
894
895impl<'a> ArrayAccessor for &'a FixedSizeBinaryArray {
896    type Item = &'a [u8];
897
898    fn value(&self, index: usize) -> Self::Item {
899        FixedSizeBinaryArray::value(self, index)
900    }
901
902    unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
903        unsafe { FixedSizeBinaryArray::value_unchecked(self, index) }
904    }
905}
906
907impl<'a> IntoIterator for &'a FixedSizeBinaryArray {
908    type Item = Option<&'a [u8]>;
909    type IntoIter = FixedSizeBinaryIter<'a>;
910
911    fn into_iter(self) -> Self::IntoIter {
912        FixedSizeBinaryIter::<'a>::new(self)
913    }
914}
915
916#[cfg(test)]
917mod tests {
918    use super::*;
919    use crate::RecordBatch;
920    use arrow_schema::{Field, Schema};
921
922    #[test]
923    fn test_fixed_size_binary_array() {
924        let values = b"hellotherearrow";
925
926        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
927            .len(3)
928            .add_buffer(Buffer::from(values))
929            .build()
930            .unwrap();
931        let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
932        assert_eq!(3, fixed_size_binary_array.len());
933        assert_eq!(0, fixed_size_binary_array.null_count());
934        assert_eq!(
935            [b'h', b'e', b'l', b'l', b'o'],
936            fixed_size_binary_array.value(0)
937        );
938        assert_eq!(
939            [b't', b'h', b'e', b'r', b'e'],
940            fixed_size_binary_array.value(1)
941        );
942        assert_eq!(
943            [b'a', b'r', b'r', b'o', b'w'],
944            fixed_size_binary_array.value(2)
945        );
946        assert_eq!(5, fixed_size_binary_array.value_length());
947        for i in 0..3 {
948            assert!(fixed_size_binary_array.is_valid(i));
949            assert!(!fixed_size_binary_array.is_null(i));
950        }
951
952        // Test binary array with offset
953        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
954            .len(2)
955            .offset(1)
956            .add_buffer(Buffer::from(values))
957            .build()
958            .unwrap();
959        let fixed_size_binary_array = FixedSizeBinaryArray::from(array_data);
960        assert_eq!(
961            [b't', b'h', b'e', b'r', b'e'],
962            fixed_size_binary_array.value(0)
963        );
964        assert_eq!(
965            [b'a', b'r', b'r', b'o', b'w'],
966            fixed_size_binary_array.value(1)
967        );
968        assert_eq!(2, fixed_size_binary_array.len());
969        assert_eq!(5, fixed_size_binary_array.value_length());
970    }
971
972    #[test]
973    fn test_fixed_size_binary_array_from_fixed_size_list_array() {
974        let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
975        let values_data = ArrayData::builder(DataType::UInt8)
976            .len(12)
977            .offset(2)
978            .add_buffer(Buffer::from_slice_ref(values))
979            .build()
980            .unwrap();
981        // [null, [10, 11, 12, 13]]
982        let array_data = unsafe {
983            ArrayData::builder(DataType::FixedSizeList(
984                Arc::new(Field::new_list_field(DataType::UInt8, false)),
985                4,
986            ))
987            .len(2)
988            .offset(1)
989            .add_child_data(values_data)
990            .null_bit_buffer(Some(Buffer::from_slice_ref([0b101])))
991            .build_unchecked()
992        };
993        let list_array = FixedSizeListArray::from(array_data);
994        let binary_array = FixedSizeBinaryArray::from(list_array);
995
996        assert_eq!(2, binary_array.len());
997        assert_eq!(1, binary_array.null_count());
998        assert!(binary_array.is_null(0));
999        assert!(binary_array.is_valid(1));
1000        assert_eq!(&[10, 11, 12, 13], binary_array.value(1));
1001    }
1002
1003    #[test]
1004    #[should_panic(
1005        expected = "FixedSizeBinaryArray can only be created from FixedSizeList<u8> arrays"
1006    )]
1007    // Different error messages, so skip for now
1008    // https://github.com/apache/arrow-rs/issues/1545
1009    #[cfg(not(feature = "force_validate"))]
1010    fn test_fixed_size_binary_array_from_incorrect_fixed_size_list_array() {
1011        let values: [u32; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
1012        let values_data = ArrayData::builder(DataType::UInt32)
1013            .len(12)
1014            .add_buffer(Buffer::from_slice_ref(values))
1015            .build()
1016            .unwrap();
1017
1018        let array_data = unsafe {
1019            ArrayData::builder(DataType::FixedSizeList(
1020                Arc::new(Field::new_list_field(DataType::Binary, false)),
1021                4,
1022            ))
1023            .len(3)
1024            .add_child_data(values_data)
1025            .build_unchecked()
1026        };
1027        let list_array = FixedSizeListArray::from(array_data);
1028        drop(FixedSizeBinaryArray::from(list_array));
1029    }
1030
1031    #[test]
1032    // Under force_validate `build_unchecked` panics on the invalid child data
1033    // before we reach the `FixedSizeBinaryArray::from` path we want to test.
1034    #[cfg(not(feature = "force_validate"))]
1035    #[should_panic(expected = "The child array cannot contain null values.")]
1036    fn test_fixed_size_binary_array_from_fixed_size_list_array_with_child_nulls_failed() {
1037        let values = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
1038        let values_data = ArrayData::builder(DataType::UInt8)
1039            .len(12)
1040            .add_buffer(Buffer::from_slice_ref(values))
1041            .null_bit_buffer(Some(Buffer::from_slice_ref([0b101010101010])))
1042            .build()
1043            .unwrap();
1044
1045        let array_data = unsafe {
1046            ArrayData::builder(DataType::FixedSizeList(
1047                Arc::new(Field::new_list_field(DataType::UInt8, false)),
1048                4,
1049            ))
1050            .len(3)
1051            .add_child_data(values_data)
1052            .build_unchecked()
1053        };
1054        let list_array = FixedSizeListArray::from(array_data);
1055        drop(FixedSizeBinaryArray::from(list_array));
1056    }
1057
1058    #[test]
1059    fn test_fixed_size_binary_array_fmt_debug() {
1060        let values = b"hellotherearrow";
1061
1062        let array_data = ArrayData::builder(DataType::FixedSizeBinary(5))
1063            .len(3)
1064            .add_buffer(Buffer::from(values))
1065            .build()
1066            .unwrap();
1067        let arr = FixedSizeBinaryArray::from(array_data);
1068        assert_eq!(
1069            "FixedSizeBinaryArray<5>\n[\n  [104, 101, 108, 108, 111],\n  [116, 104, 101, 114, 101],\n  [97, 114, 114, 111, 119],\n]",
1070            format!("{arr:?}")
1071        );
1072    }
1073
1074    #[test]
1075    fn test_fixed_size_binary_array_from_iter() {
1076        let input_arg = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
1077        let arr = FixedSizeBinaryArray::try_from_iter(input_arg.into_iter()).unwrap();
1078
1079        assert_eq!(2, arr.value_length());
1080        assert_eq!(3, arr.len())
1081    }
1082
1083    #[test]
1084    fn test_all_none_fixed_size_binary_array_from_sparse_iter() {
1085        let none_option: Option<[u8; 32]> = None;
1086        let input_arg = vec![none_option, none_option, none_option];
1087        #[expect(deprecated)]
1088        let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.into_iter()).unwrap();
1089        assert_eq!(0, arr.value_length());
1090        assert_eq!(3, arr.len())
1091    }
1092
1093    #[test]
1094    fn test_fixed_size_binary_array_from_sparse_iter() {
1095        let input_arg = vec![
1096            None,
1097            Some(vec![7, 8]),
1098            Some(vec![9, 10]),
1099            None,
1100            Some(vec![13, 14]),
1101        ];
1102        #[expect(deprecated)]
1103        let arr = FixedSizeBinaryArray::try_from_sparse_iter(input_arg.iter().cloned()).unwrap();
1104        assert_eq!(2, arr.value_length());
1105        assert_eq!(5, arr.len());
1106
1107        let arr =
1108            FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 2).unwrap();
1109        assert_eq!(2, arr.value_length());
1110        assert_eq!(5, arr.len());
1111    }
1112
1113    #[test]
1114    fn test_fixed_size_binary_array_from_sparse_iter_with_size_all_none() {
1115        let input_arg = vec![None, None, None, None, None] as Vec<Option<Vec<u8>>>;
1116
1117        let arr = FixedSizeBinaryArray::try_from_sparse_iter_with_size(input_arg.into_iter(), 16)
1118            .unwrap();
1119        assert_eq!(16, arr.value_length());
1120        assert_eq!(5, arr.len())
1121    }
1122
1123    #[test]
1124    fn test_fixed_size_binary_array_from_vec() {
1125        let values = vec![b"one".as_slice(), b"two", b"six", b"ten"];
1126        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1127        assert_eq!(array.len(), 4);
1128        assert_eq!(array.null_count(), 0);
1129        assert_eq!(array.logical_null_count(), 0);
1130        assert_eq!(array.value(0), b"one");
1131        assert_eq!(array.value(1), b"two");
1132        assert_eq!(array.value(2), b"six");
1133        assert_eq!(array.value(3), b"ten");
1134        assert!(!array.is_null(0));
1135        assert!(!array.is_null(1));
1136        assert!(!array.is_null(2));
1137        assert!(!array.is_null(3));
1138    }
1139
1140    #[test]
1141    fn test_fixed_size_binary_array_from_vec_incorrect_length() {
1142        let values = vec![b"one".as_slice(), b"two", b"three", b"four"];
1143        assert!(FixedSizeBinaryArray::try_from(values).is_err());
1144    }
1145
1146    #[test]
1147    fn test_fixed_size_binary_array_from_opt_vec() {
1148        let values = vec![
1149            Some(b"one".as_slice()),
1150            Some(b"two"),
1151            None,
1152            Some(b"six"),
1153            Some(b"ten"),
1154        ];
1155        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1156        assert_eq!(array.len(), 5);
1157        assert_eq!(array.value(0), b"one");
1158        assert_eq!(array.value(1), b"two");
1159        assert_eq!(array.value(3), b"six");
1160        assert_eq!(array.value(4), b"ten");
1161        assert!(!array.is_null(0));
1162        assert!(!array.is_null(1));
1163        assert!(array.is_null(2));
1164        assert!(!array.is_null(3));
1165        assert!(!array.is_null(4));
1166    }
1167
1168    #[test]
1169    fn test_fixed_size_binary_array_from_opt_vec_incorrect_length() {
1170        let values = vec![
1171            Some(b"one".as_slice()),
1172            Some(b"two"),
1173            None,
1174            Some(b"three"),
1175            Some(b"four"),
1176        ];
1177        assert!(FixedSizeBinaryArray::try_from(values).is_err());
1178    }
1179
1180    #[test]
1181    fn fixed_size_binary_array_all_null() {
1182        let data = vec![None] as Vec<Option<String>>;
1183        let array =
1184            FixedSizeBinaryArray::try_from_sparse_iter_with_size(data.into_iter(), 0).unwrap();
1185        array
1186            .into_data()
1187            .validate_full()
1188            .expect("All null array has valid array data");
1189    }
1190
1191    #[test]
1192    // Test for https://github.com/apache/arrow-rs/issues/1390
1193    fn fixed_size_binary_array_all_null_in_batch_with_schema() {
1194        let schema = Schema::new(vec![Field::new("a", DataType::FixedSizeBinary(2), true)]);
1195
1196        let none_option: Option<[u8; 2]> = None;
1197        let item = FixedSizeBinaryArray::try_from_sparse_iter_with_size(
1198            vec![none_option, none_option, none_option].into_iter(),
1199            2,
1200        )
1201        .unwrap();
1202
1203        // Should not panic
1204        RecordBatch::try_new(Arc::new(schema), vec![Arc::new(item)]).unwrap();
1205    }
1206
1207    #[test]
1208    #[should_panic(
1209        expected = "Trying to access an element at index 4 from a FixedSizeBinaryArray of length 3"
1210    )]
1211    fn test_fixed_size_binary_array_get_value_index_out_of_bound() {
1212        let values = vec![Some(b"one".as_slice()), Some(b"two"), None];
1213        let array = FixedSizeBinaryArray::try_from(values).unwrap();
1214
1215        array.value(4);
1216    }
1217
1218    #[test]
1219    fn test_constructors() {
1220        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1221        let a = FixedSizeBinaryArray::new(2, buffer.clone(), None);
1222        assert_eq!(a.len(), 5);
1223
1224        let nulls = NullBuffer::new_null(5);
1225        FixedSizeBinaryArray::new(2, buffer.clone(), Some(nulls));
1226
1227        let null_array = FixedSizeBinaryArray::new_null(4, 3);
1228        assert_eq!(null_array.len(), 3);
1229        assert_eq!(null_array.values().len(), 12);
1230
1231        let a = FixedSizeBinaryArray::new(3, buffer.clone(), None);
1232        assert_eq!(a.len(), 3);
1233
1234        let nulls = NullBuffer::new_null(3);
1235        FixedSizeBinaryArray::new(3, buffer.clone(), Some(nulls));
1236
1237        let err = FixedSizeBinaryArray::try_new(-1, buffer.clone(), None).unwrap_err();
1238
1239        assert_eq!(
1240            err.to_string(),
1241            "Invalid argument error: Value length cannot be negative, got -1"
1242        );
1243
1244        let nulls = NullBuffer::new_null(3);
1245        let err = FixedSizeBinaryArray::try_new(2, buffer.clone(), Some(nulls)).unwrap_err();
1246        assert_eq!(
1247            err.to_string(),
1248            "Invalid argument error: Incorrect length of null buffer for FixedSizeBinaryArray, expected 5 got 3"
1249        );
1250
1251        let zero_sized = FixedSizeBinaryArray::new(0, Buffer::default(), None);
1252        assert_eq!(zero_sized.len(), 0);
1253        assert_eq!(zero_sized.null_count(), 0);
1254        assert_eq!(zero_sized.values().len(), 0);
1255
1256        let nulls = NullBuffer::new_null(3);
1257        let zero_sized_with_nulls = FixedSizeBinaryArray::new(0, Buffer::default(), Some(nulls));
1258        assert_eq!(zero_sized_with_nulls.len(), 3);
1259        assert_eq!(zero_sized_with_nulls.null_count(), 3);
1260        assert_eq!(zero_sized_with_nulls.values().len(), 0);
1261
1262        let zero_sized_with_non_empty_buffer_err =
1263            FixedSizeBinaryArray::try_new(0, buffer, None).unwrap_err();
1264        assert_eq!(
1265            zero_sized_with_non_empty_buffer_err.to_string(),
1266            "Invalid argument error: Buffer cannot have non-zero length if the value length is zero"
1267        );
1268    }
1269
1270    #[test]
1271    fn test_try_new_with_len() {
1272        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1273
1274        let a = FixedSizeBinaryArray::try_new_with_len(2, buffer.clone(), None, 5).unwrap();
1275        assert_eq!(a.len(), 5);
1276
1277        let nulls = NullBuffer::new_null(5);
1278        let a = FixedSizeBinaryArray::try_new_with_len(2, buffer, Some(nulls), 5).unwrap();
1279        assert_eq!(a.len(), 5);
1280        assert_eq!(a.null_count(), 5);
1281
1282        let a = FixedSizeBinaryArray::try_new_with_len(2, Buffer::default(), None, 0).unwrap();
1283        assert_eq!(a.len(), 0);
1284    }
1285
1286    #[test]
1287    fn test_try_new_with_len_zero_width() {
1288        // Zero-width with no nulls: the case where the length cannot be inferred from the parts
1289        let a = FixedSizeBinaryArray::try_new_with_len(0, Buffer::default(), None, 5).unwrap();
1290        assert_eq!(a.len(), 5);
1291        assert_eq!(a.null_count(), 0);
1292        assert_eq!(a.values().len(), 0);
1293
1294        let nulls = NullBuffer::new_null(3);
1295        let a =
1296            FixedSizeBinaryArray::try_new_with_len(0, Buffer::default(), Some(nulls), 3).unwrap();
1297        assert_eq!(a.len(), 3);
1298        assert_eq!(a.null_count(), 3);
1299    }
1300
1301    #[test]
1302    fn test_try_new_with_len_negative_value_length() {
1303        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1304        let err = FixedSizeBinaryArray::try_new_with_len(-1, buffer, None, 5).unwrap_err();
1305        assert_eq!(
1306            err.to_string(),
1307            "Invalid argument error: Value length cannot be negative, got -1"
1308        );
1309    }
1310
1311    #[test]
1312    fn test_try_new_with_len_incorrect_null_buffer_length() {
1313        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1314        let nulls = NullBuffer::new_null(3);
1315        let err = FixedSizeBinaryArray::try_new_with_len(2, buffer, Some(nulls), 5).unwrap_err();
1316        assert_eq!(
1317            err.to_string(),
1318            "Invalid argument error: Incorrect length of null buffer for FixedSizeBinaryArray, expected 5 got 3"
1319        );
1320    }
1321
1322    #[test]
1323    fn test_try_new_with_len_incorrect_values_buffer_length() {
1324        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1325        let err = FixedSizeBinaryArray::try_new_with_len(2, buffer, None, 3).unwrap_err();
1326        assert_eq!(
1327            err.to_string(),
1328            "Invalid argument error: Incorrect length of values buffer for FixedSizeBinaryArray, expected 3 got 5"
1329        );
1330    }
1331
1332    #[test]
1333    fn test_try_new_with_len_zero_width_non_empty_buffer() {
1334        let buffer = Buffer::from_vec(vec![0_u8; 10]);
1335        let err = FixedSizeBinaryArray::try_new_with_len(0, buffer, None, 5).unwrap_err();
1336        assert_eq!(
1337            err.to_string(),
1338            "Invalid argument error: Buffer cannot have non-zero length if the value length is zero"
1339        );
1340    }
1341}