Skip to main content

arrow_array/builder/
fixed_size_binary_dictionary_builder.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::builder::{ArrayBuilder, FixedSizeBinaryBuilder, PrimitiveBuilder};
19use crate::types::ArrowDictionaryKeyType;
20use crate::{Array, ArrayRef, DictionaryArray, PrimitiveArray};
21use arrow_buffer::ArrowNativeType;
22use arrow_schema::DataType::FixedSizeBinary;
23use arrow_schema::{ArrowError, DataType};
24use hashbrown::HashTable;
25use num_traits::NumCast;
26use std::any::Any;
27use std::sync::Arc;
28
29/// Builder for [`DictionaryArray`] of [`FixedSizeBinaryArray`]
30///
31/// The output array has a dictionary of unique, fixed-size binary values. The
32/// builder handles deduplication.
33///
34/// # Example
35/// ```
36/// # use arrow_array::builder::{FixedSizeBinaryDictionaryBuilder};
37/// # use arrow_array::array::{Array, FixedSizeBinaryArray};
38/// # use arrow_array::DictionaryArray;
39/// # use arrow_array::types::Int8Type;
40/// // Build 3 byte FixedBinaryArrays
41/// let byte_width = 3;
42/// let mut builder = FixedSizeBinaryDictionaryBuilder::<Int8Type>::new(3);
43/// builder.append("abc").unwrap();
44/// builder.append_null();
45/// builder.append(b"def").unwrap();
46/// builder.append(b"def").unwrap(); // duplicate value
47/// // Result is a Dictionary Array
48/// let array = builder.finish();
49/// let dict_array = array.as_any().downcast_ref::<DictionaryArray<Int8Type>>().unwrap();
50/// // The array represents "abc", null, "def", "def"
51/// assert_eq!(array.keys().len(), 4);
52/// // but there are only 2 unique values
53/// assert_eq!(array.values().len(), 2);
54/// let values = dict_array.values().as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
55/// assert_eq!(values.value(0), "abc".as_bytes());
56/// assert_eq!(values.value(1), "def".as_bytes());
57/// ```
58///
59/// [`FixedSizeBinaryArray`]: crate::FixedSizeBinaryArray
60#[derive(Debug)]
61pub struct FixedSizeBinaryDictionaryBuilder<K>
62where
63    K: ArrowDictionaryKeyType,
64{
65    state: ahash::RandomState,
66    dedup: HashTable<usize>,
67
68    keys_builder: PrimitiveBuilder<K>,
69    values_builder: FixedSizeBinaryBuilder,
70    byte_width: i32,
71}
72
73impl<K> FixedSizeBinaryDictionaryBuilder<K>
74where
75    K: ArrowDictionaryKeyType,
76{
77    /// Creates a new `FixedSizeBinaryDictionaryBuilder`
78    pub fn new(byte_width: i32) -> Self {
79        let keys_builder = PrimitiveBuilder::new();
80        let values_builder = FixedSizeBinaryBuilder::new(byte_width);
81        Self {
82            state: Default::default(),
83            dedup: HashTable::with_capacity(keys_builder.capacity()),
84            keys_builder,
85            values_builder,
86            byte_width,
87        }
88    }
89
90    /// Creates a new `FixedSizeBinaryDictionaryBuilder` with the provided capacities
91    ///
92    /// `keys_capacity`: the number of keys, i.e. length of array to build
93    /// `value_capacity`: the number of distinct dictionary values, i.e. size of dictionary
94    /// `byte_width`: the byte width for individual values in the values array
95    pub fn with_capacity(keys_capacity: usize, value_capacity: usize, byte_width: i32) -> Self {
96        Self {
97            state: Default::default(),
98            dedup: Default::default(),
99            keys_builder: PrimitiveBuilder::with_capacity(keys_capacity),
100            values_builder: FixedSizeBinaryBuilder::with_capacity(value_capacity, byte_width),
101            byte_width,
102        }
103    }
104
105    /// Creates a new `FixedSizeBinaryDictionaryBuilder` from the existing builder with the same
106    /// keys and values, but with a new data type for the keys.
107    ///
108    /// # Example
109    /// ```
110    /// # use arrow_array::builder::FixedSizeBinaryDictionaryBuilder;
111    /// # use arrow_array::types::{UInt8Type, UInt16Type, UInt64Type};
112    /// # use arrow_array::UInt16Array;
113    /// # use arrow_schema::ArrowError;
114    ///
115    /// let mut u8_keyed_builder = FixedSizeBinaryDictionaryBuilder::<UInt8Type>::new(2);
116    /// // appending too many values causes the dictionary to overflow
117    /// for i in 0..=255 {
118    ///     u8_keyed_builder.append_value(vec![0, i]);
119    /// }
120    /// let result = u8_keyed_builder.append(vec![1, 0]);
121    /// assert!(matches!(result, Err(ArrowError::DictionaryKeyOverflowError{})));
122    ///
123    /// // we need to upgrade to a larger key type
124    /// let mut u16_keyed_builder = FixedSizeBinaryDictionaryBuilder::<UInt16Type>::try_new_from_builder(u8_keyed_builder).unwrap();
125    /// let dictionary_array = u16_keyed_builder.finish();
126    /// let keys = dictionary_array.keys();
127    ///
128    /// assert_eq!(keys, &UInt16Array::from_iter(0..256));
129    /// ```
130    pub fn try_new_from_builder<K2>(
131        mut source: FixedSizeBinaryDictionaryBuilder<K2>,
132    ) -> Result<Self, ArrowError>
133    where
134        K::Native: NumCast,
135        K2: ArrowDictionaryKeyType,
136        K2::Native: NumCast,
137    {
138        let state = source.state;
139        let dedup = source.dedup;
140        let values_builder = source.values_builder;
141        let byte_width = source.byte_width;
142
143        let source_keys = source.keys_builder.finish();
144        let new_keys: PrimitiveArray<K> = source_keys.try_unary(|value| {
145            num_traits::cast::cast::<K2::Native, K::Native>(value).ok_or_else(|| {
146                ArrowError::CastError(format!(
147                    "Can't cast dictionary keys from source type {:?} to type {:?}",
148                    K2::DATA_TYPE,
149                    K::DATA_TYPE
150                ))
151            })
152        })?;
153
154        // drop source key here because currently source_keys and new_keys are holding reference to
155        // the same underlying null_buffer. Below we want to call new_keys.into_builder() it must
156        // be the only reference holder.
157        drop(source_keys);
158
159        Ok(Self {
160            state,
161            dedup,
162            keys_builder: new_keys.into_builder().map_err(|_| {
163                ArrowError::ComputeError(
164                    "Internal Error: the keys just derived from the source builder are \
165                     unexpectedly shared, so they cannot be reused as a builder"
166                        .to_string(),
167                )
168            })?,
169            values_builder,
170            byte_width,
171        })
172    }
173}
174
175impl<K> ArrayBuilder for FixedSizeBinaryDictionaryBuilder<K>
176where
177    K: ArrowDictionaryKeyType,
178{
179    /// Returns the builder as an non-mutable `Any` reference.
180    fn as_any(&self) -> &dyn Any {
181        self
182    }
183
184    /// Returns the builder as an mutable `Any` reference.
185    fn as_any_mut(&mut self) -> &mut dyn Any {
186        self
187    }
188
189    /// Returns the boxed builder as a box of `Any`.
190    fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
191        self
192    }
193
194    /// Returns the number of array slots in the builder
195    fn len(&self) -> usize {
196        self.keys_builder.len()
197    }
198
199    /// Builds the array and reset this builder.
200    fn finish(&mut self) -> ArrayRef {
201        Arc::new(self.finish())
202    }
203
204    /// Builds the array without resetting the builder.
205    fn finish_cloned(&self) -> ArrayRef {
206        Arc::new(self.finish_cloned())
207    }
208
209    fn finish_preserve_values(&mut self) -> ArrayRef {
210        Arc::new(self.finish_preserve_values())
211    }
212}
213
214impl<K> FixedSizeBinaryDictionaryBuilder<K>
215where
216    K: ArrowDictionaryKeyType,
217{
218    fn get_or_insert_key(&mut self, value: impl AsRef<[u8]>) -> Result<K::Native, ArrowError> {
219        let value_bytes: &[u8] = value.as_ref();
220
221        let state = &self.state;
222        let storage = &mut self.values_builder;
223        let hash = state.hash_one(value_bytes);
224
225        let idx = *self
226            .dedup
227            .entry(
228                hash,
229                |idx| value_bytes == get_bytes(storage, self.byte_width, *idx),
230                |idx| state.hash_one(get_bytes(storage, self.byte_width, *idx)),
231            )
232            .or_insert_with(|| {
233                let idx = storage.len();
234                let _ = storage.append_value(value);
235                idx
236            })
237            .get();
238
239        let key = K::Native::from_usize(idx).ok_or(ArrowError::DictionaryKeyOverflowError)?;
240
241        Ok(key)
242    }
243
244    /// Append a value to the array. Return an existing index
245    /// if already present in the values array or a new index if the
246    /// value is appended to the values array.
247    ///
248    /// Returns an error if the new index would overflow the key type.
249    pub fn append(&mut self, value: impl AsRef<[u8]>) -> Result<K::Native, ArrowError> {
250        if self.byte_width != value.as_ref().len() as i32 {
251            Err(ArrowError::InvalidArgumentError(format!(
252                "Invalid input length passed to FixedSizeBinaryBuilder. Expected {} got {}",
253                self.byte_width,
254                value.as_ref().len()
255            )))
256        } else {
257            let key = self.get_or_insert_key(value)?;
258            self.keys_builder.append_value(key);
259            Ok(key)
260        }
261    }
262
263    /// Append a value multiple times to the array.
264    /// This is the same as [`Self::append`] but allows to append the same value multiple times without doing multiple lookups.
265    ///
266    /// Returns an error if the new index would overflow the key type.
267    pub fn append_n(
268        &mut self,
269        value: impl AsRef<[u8]>,
270        count: usize,
271    ) -> Result<K::Native, ArrowError> {
272        if self.byte_width != value.as_ref().len() as i32 {
273            Err(ArrowError::InvalidArgumentError(format!(
274                "Invalid input length passed to FixedSizeBinaryBuilder. Expected {} got {}",
275                self.byte_width,
276                value.as_ref().len()
277            )))
278        } else {
279            let key = self.get_or_insert_key(value)?;
280            self.keys_builder.append_value_n(key, count);
281            Ok(key)
282        }
283    }
284
285    /// Appends a null slot into the builder
286    #[inline]
287    pub fn append_null(&mut self) {
288        self.keys_builder.append_null()
289    }
290
291    /// Appends `n` `null`s into the builder.
292    #[inline]
293    pub fn append_nulls(&mut self, n: usize) {
294        self.keys_builder.append_nulls(n);
295    }
296
297    /// Infallibly append a value to this builder
298    ///
299    /// # Panics
300    ///
301    /// Panics if the resulting length of the dictionary values array would exceed `T::Native::MAX`
302    pub fn append_value(&mut self, value: impl AsRef<[u8]>) {
303        self.append(value).expect("dictionary key overflow");
304    }
305
306    /// Builds the `DictionaryArray` and reset this builder.
307    pub fn finish(&mut self) -> DictionaryArray<K> {
308        self.dedup.clear();
309        let values = self.values_builder.finish();
310        let keys = self.keys_builder.finish();
311
312        let data_type = DataType::Dictionary(
313            Box::new(K::DATA_TYPE),
314            Box::new(FixedSizeBinary(self.byte_width)),
315        );
316
317        let builder = keys
318            .into_data()
319            .into_builder()
320            .data_type(data_type)
321            .child_data(vec![values.into_data()]);
322
323        // SAFETY: builder is constructed from valid key/value arrays produced by the builder
324        DictionaryArray::from(unsafe { builder.build_unchecked() })
325    }
326
327    /// Builds the `DictionaryArray` without resetting the builder.
328    pub fn finish_cloned(&self) -> DictionaryArray<K> {
329        let values = self.values_builder.finish_cloned();
330        let keys = self.keys_builder.finish_cloned();
331
332        let data_type = DataType::Dictionary(
333            Box::new(K::DATA_TYPE),
334            Box::new(FixedSizeBinary(self.byte_width)),
335        );
336
337        let builder = keys
338            .into_data()
339            .into_builder()
340            .data_type(data_type)
341            .child_data(vec![values.into_data()]);
342
343        // SAFETY: builder is constructed from valid key/value arrays produced by the builder
344        DictionaryArray::from(unsafe { builder.build_unchecked() })
345    }
346
347    /// Builds the `DictionaryArray` without resetting the values builder or
348    /// the internal de-duplication map.
349    ///
350    /// The advantage of doing this is that the values will represent the entire
351    /// set of what has been built so-far by this builder and ensures
352    /// consistency in the assignment of keys to values across multiple calls
353    /// to `finish_preserve_values`. This enables ipc writers to efficiently
354    /// emit delta dictionaries.
355    ///
356    /// The downside to this is that building the record requires creating a
357    /// copy of the values, which can become slowly more expensive if the
358    /// dictionary grows.
359    ///
360    /// Additionally, if record batches from multiple different dictionary
361    /// builders for the same column are fed into a single ipc writer, beware
362    /// that entire dictionaries are likely to be re-sent frequently even when
363    /// the majority of the values are not used by the current record batch.
364    pub fn finish_preserve_values(&mut self) -> DictionaryArray<K> {
365        let values = self.values_builder.finish_cloned();
366        let keys = self.keys_builder.finish();
367
368        let data_type = DataType::Dictionary(
369            Box::new(K::DATA_TYPE),
370            Box::new(FixedSizeBinary(self.byte_width)),
371        );
372
373        let builder = keys
374            .into_data()
375            .into_builder()
376            .data_type(data_type)
377            .child_data(vec![values.into_data()]);
378
379        // SAFETY: builder is constructed from valid key/value arrays produced by the builder
380        DictionaryArray::from(unsafe { builder.build_unchecked() })
381    }
382}
383
384fn get_bytes(values: &FixedSizeBinaryBuilder, byte_width: i32, idx: usize) -> &[u8] {
385    let values = values.values_slice();
386    let start = idx * byte_width.as_usize();
387    let end = idx * byte_width.as_usize() + byte_width.as_usize();
388    &values[start..end]
389}
390
391#[cfg(test)]
392mod tests {
393    use super::*;
394
395    use crate::types::{Int8Type, Int16Type, Int32Type, UInt8Type, UInt16Type};
396    use crate::{ArrowPrimitiveType, FixedSizeBinaryArray, Int8Array};
397
398    #[test]
399    fn test_fixed_size_dictionary_builder() {
400        let values = ["abc", "def"];
401
402        let mut b = FixedSizeBinaryDictionaryBuilder::<Int8Type>::new(3);
403        assert_eq!(b.append(values[0]).unwrap(), 0);
404        b.append_null();
405        assert_eq!(b.append(values[1]).unwrap(), 1);
406        assert_eq!(b.append(values[1]).unwrap(), 1);
407        assert_eq!(b.append(values[0]).unwrap(), 0);
408        b.append_nulls(2);
409        assert_eq!(b.append(values[0]).unwrap(), 0);
410        let array = b.finish();
411
412        assert_eq!(
413            array.keys(),
414            &Int8Array::from(vec![
415                Some(0),
416                None,
417                Some(1),
418                Some(1),
419                Some(0),
420                None,
421                None,
422                Some(0)
423            ]),
424        );
425
426        // Values are polymorphic and so require a downcast.
427        let ava = array
428            .values()
429            .as_any()
430            .downcast_ref::<FixedSizeBinaryArray>()
431            .unwrap();
432
433        assert_eq!(ava.value(0), values[0].as_bytes());
434        assert_eq!(ava.value(1), values[1].as_bytes());
435    }
436
437    #[test]
438    fn test_fixed_size_dictionary_builder_append_n() {
439        let values = ["abc", "def"];
440        let mut b = FixedSizeBinaryDictionaryBuilder::<Int8Type>::new(3);
441        assert_eq!(b.append_n(values[0], 2).unwrap(), 0);
442        assert_eq!(b.append_n(values[1], 3).unwrap(), 1);
443        assert_eq!(b.append_n(values[0], 2).unwrap(), 0);
444        let array = b.finish();
445
446        assert_eq!(
447            array.keys(),
448            &Int8Array::from(vec![
449                Some(0),
450                Some(0),
451                Some(1),
452                Some(1),
453                Some(1),
454                Some(0),
455                Some(0),
456            ]),
457        );
458
459        // Values are polymorphic and so require a downcast.
460        let ava = array
461            .values()
462            .as_any()
463            .downcast_ref::<FixedSizeBinaryArray>()
464            .unwrap();
465
466        assert_eq!(ava.value(0), values[0].as_bytes());
467        assert_eq!(ava.value(1), values[1].as_bytes());
468    }
469
470    #[test]
471    fn test_fixed_size_dictionary_builder_wrong_size() {
472        let mut b = FixedSizeBinaryDictionaryBuilder::<Int8Type>::new(3);
473        let err = b.append(b"too long").unwrap_err().to_string();
474        assert_eq!(
475            err,
476            "Invalid argument error: Invalid input length passed to FixedSizeBinaryBuilder. Expected 3 got 8"
477        );
478        let err = b.append("").unwrap_err().to_string();
479        assert_eq!(
480            err,
481            "Invalid argument error: Invalid input length passed to FixedSizeBinaryBuilder. Expected 3 got 0"
482        );
483        let err = b.append_n("a", 3).unwrap_err().to_string();
484        assert_eq!(
485            err,
486            "Invalid argument error: Invalid input length passed to FixedSizeBinaryBuilder. Expected 3 got 1"
487        );
488    }
489
490    #[test]
491    fn test_fixed_size_dictionary_builder_finish_cloned() {
492        let values = ["abc", "def", "ghi"];
493
494        let mut builder = FixedSizeBinaryDictionaryBuilder::<Int8Type>::new(3);
495
496        builder.append(values[0]).unwrap();
497        builder.append_null();
498        builder.append(values[1]).unwrap();
499        builder.append(values[1]).unwrap();
500        builder.append(values[0]).unwrap();
501        let mut array = builder.finish_cloned();
502
503        assert_eq!(
504            array.keys(),
505            &Int8Array::from(vec![Some(0), None, Some(1), Some(1), Some(0)])
506        );
507
508        // Values are polymorphic and so require a downcast.
509        let ava = array
510            .values()
511            .as_any()
512            .downcast_ref::<FixedSizeBinaryArray>()
513            .unwrap();
514
515        assert_eq!(ava.value(0), values[0].as_bytes());
516        assert_eq!(ava.value(1), values[1].as_bytes());
517
518        builder.append(values[0]).unwrap();
519        builder.append(values[2]).unwrap();
520        builder.append(values[1]).unwrap();
521
522        array = builder.finish();
523
524        assert_eq!(
525            array.keys(),
526            &Int8Array::from(vec![
527                Some(0),
528                None,
529                Some(1),
530                Some(1),
531                Some(0),
532                Some(0),
533                Some(2),
534                Some(1)
535            ])
536        );
537
538        // Values are polymorphic and so require a downcast.
539        let ava2 = array
540            .values()
541            .as_any()
542            .downcast_ref::<FixedSizeBinaryArray>()
543            .unwrap();
544
545        assert_eq!(ava2.value(0), values[0].as_bytes());
546        assert_eq!(ava2.value(1), values[1].as_bytes());
547        assert_eq!(ava2.value(2), values[2].as_bytes());
548    }
549
550    fn _test_try_new_from_builder_generic_for_key_types<K1, K2>(values: Vec<[u8; 3]>)
551    where
552        K1: ArrowDictionaryKeyType,
553        K1::Native: NumCast,
554        K2: ArrowDictionaryKeyType,
555        K2::Native: NumCast + From<u8>,
556    {
557        let mut source = FixedSizeBinaryDictionaryBuilder::<K1>::new(3);
558        source.append_value(values[0]);
559        source.append_null();
560        source.append_value(values[1]);
561        source.append_value(values[2]);
562
563        let mut result =
564            FixedSizeBinaryDictionaryBuilder::<K2>::try_new_from_builder(source).unwrap();
565        let array = result.finish();
566
567        let mut expected_keys_builder = PrimitiveBuilder::<K2>::new();
568        expected_keys_builder
569            .append_value(<<K2 as ArrowPrimitiveType>::Native as From<u8>>::from(0u8));
570        expected_keys_builder.append_null();
571        expected_keys_builder
572            .append_value(<<K2 as ArrowPrimitiveType>::Native as From<u8>>::from(1u8));
573        expected_keys_builder
574            .append_value(<<K2 as ArrowPrimitiveType>::Native as From<u8>>::from(2u8));
575        let expected_keys = expected_keys_builder.finish();
576        assert_eq!(array.keys(), &expected_keys);
577
578        let av = array.values();
579        let ava = av.as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
580        assert_eq!(ava.value(0), values[0]);
581        assert_eq!(ava.value(1), values[1]);
582        assert_eq!(ava.value(2), values[2]);
583    }
584
585    #[test]
586    fn test_try_new_from_builder() {
587        let values = vec![[1, 2, 3], [5, 6, 7], [6, 7, 8]];
588        // test cast to bigger size unsigned
589        _test_try_new_from_builder_generic_for_key_types::<UInt8Type, UInt16Type>(values.clone());
590        // test cast going to smaller size unsigned
591        _test_try_new_from_builder_generic_for_key_types::<UInt16Type, UInt8Type>(values.clone());
592        // test cast going to bigger size signed
593        _test_try_new_from_builder_generic_for_key_types::<Int8Type, Int16Type>(values.clone());
594        // test cast going to smaller size signed
595        _test_try_new_from_builder_generic_for_key_types::<Int32Type, Int16Type>(values.clone());
596        // test going from signed to signed for different size changes
597        _test_try_new_from_builder_generic_for_key_types::<UInt8Type, Int16Type>(values.clone());
598        _test_try_new_from_builder_generic_for_key_types::<Int8Type, UInt8Type>(values.clone());
599        _test_try_new_from_builder_generic_for_key_types::<Int8Type, UInt16Type>(values.clone());
600        _test_try_new_from_builder_generic_for_key_types::<Int32Type, Int16Type>(values.clone());
601    }
602
603    #[test]
604    fn test_try_new_from_builder_cast_fails() {
605        let mut source_builder = FixedSizeBinaryDictionaryBuilder::<UInt16Type>::new(2);
606        for i in 0u16..257u16 {
607            source_builder.append_value(vec![(i >> 8) as u8, i as u8]);
608        }
609
610        // there should be too many values that we can't downcast to the underlying type
611        // we have keys that wouldn't fit into UInt8Type
612        let result =
613            FixedSizeBinaryDictionaryBuilder::<UInt8Type>::try_new_from_builder(source_builder);
614        assert!(result.is_err());
615        if let Err(e) = result {
616            assert!(matches!(e, ArrowError::CastError(_)));
617            assert_eq!(
618                e.to_string(),
619                "Cast error: Can't cast dictionary keys from source type UInt16 to type UInt8"
620            );
621        }
622    }
623
624    #[test]
625    fn test_finish_preserve_values() {
626        // Create the first dictionary
627        let mut builder = FixedSizeBinaryDictionaryBuilder::<Int32Type>::new(3);
628        builder.append_value("aaa");
629        builder.append_value("bbb");
630        builder.append_value("ccc");
631        let dict = builder.finish_preserve_values();
632        assert_eq!(dict.keys().values(), &[0, 1, 2]);
633        let values = dict
634            .downcast_dict::<FixedSizeBinaryArray>()
635            .unwrap()
636            .into_iter()
637            .collect::<Vec<_>>();
638        assert_eq!(
639            values,
640            vec![
641                Some(b"aaa".as_slice()),
642                Some(b"bbb".as_slice()),
643                Some(b"ccc".as_slice())
644            ]
645        );
646
647        // Create a new dictionary
648        builder.append_value("ddd");
649        builder.append_value("eee");
650        let dict2 = builder.finish_preserve_values();
651
652        // Make sure the keys are assigned after the old ones and we have the
653        // right values
654        assert_eq!(dict2.keys().values(), &[3, 4]);
655        let values = dict2
656            .downcast_dict::<FixedSizeBinaryArray>()
657            .unwrap()
658            .into_iter()
659            .collect::<Vec<_>>();
660        assert_eq!(values, [Some(b"ddd".as_slice()), Some(b"eee".as_slice())]);
661
662        // Check that we have all of the expected values
663        let all_values = dict2
664            .values()
665            .as_any()
666            .downcast_ref::<FixedSizeBinaryArray>()
667            .unwrap()
668            .into_iter()
669            .collect::<Vec<_>>();
670        assert_eq!(
671            all_values,
672            [
673                Some(b"aaa".as_slice()),
674                Some(b"bbb".as_slice()),
675                Some(b"ccc".as_slice()),
676                Some(b"ddd".as_slice()),
677                Some(b"eee".as_slice())
678            ]
679        );
680    }
681}