Skip to main content

arrow_array/
cast.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
18//! Defines helper functions for downcasting [`dyn Array`](Array) to concrete types
19
20use crate::array::*;
21use crate::types::*;
22use arrow_data::ArrayData;
23
24/// Re-export symbols needed for downcast macros
25///
26/// Name follows `serde` convention
27#[doc(hidden)]
28pub mod __private {
29    pub use arrow_schema::{DataType, IntervalUnit, TimeUnit};
30}
31
32/// Repeats the provided pattern based on the number of comma separated identifiers
33#[doc(hidden)]
34#[macro_export]
35macro_rules! repeat_pat {
36    ($e:pat, $v_:expr) => {
37        $e
38    };
39    ($e:pat, $v_:expr $(, $tail:expr)+) => {
40        ($e, $crate::repeat_pat!($e $(, $tail)+))
41    }
42}
43
44/// Given one or more expressions evaluating to an integer [`DataType`] invokes the provided macro
45/// `m` with the corresponding integer [`ArrowPrimitiveType`], followed by any additional arguments
46///
47/// ```
48/// # use arrow_array::{downcast_primitive, ArrowPrimitiveType, downcast_integer};
49/// # use arrow_schema::DataType;
50///
51/// macro_rules! dictionary_key_size_helper {
52///   ($t:ty, $o:ty) => {
53///       std::mem::size_of::<<$t as ArrowPrimitiveType>::Native>() as $o
54///   };
55/// }
56///
57/// fn dictionary_key_size(t: &DataType) -> u8 {
58///     match t {
59///         DataType::Dictionary(k, _) => downcast_integer! {
60///             k.as_ref() => (dictionary_key_size_helper, u8),
61///             _ => unreachable!(),
62///         },
63///         // You can also add a guard to the pattern
64///         DataType::LargeUtf8 if true => u8::MAX,
65///         _ => u8::MAX,
66///     }
67/// }
68///
69/// assert_eq!(dictionary_key_size(&DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8))), 4);
70/// assert_eq!(dictionary_key_size(&DataType::Dictionary(Box::new(DataType::Int64), Box::new(DataType::Utf8))), 8);
71/// assert_eq!(dictionary_key_size(&DataType::Dictionary(Box::new(DataType::UInt16), Box::new(DataType::Utf8))), 2);
72/// ```
73///
74/// [`DataType`]: arrow_schema::DataType
75#[macro_export]
76macro_rules! downcast_integer {
77    ($($data_type:expr),+ => ($m:path $(, $args:tt)*), $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
78        match ($($data_type),+) {
79            $crate::repeat_pat!($crate::cast::__private::DataType::Int8, $($data_type),+) => {
80                $m!($crate::types::Int8Type $(, $args)*)
81            }
82            $crate::repeat_pat!($crate::cast::__private::DataType::Int16, $($data_type),+) => {
83                $m!($crate::types::Int16Type $(, $args)*)
84            }
85            $crate::repeat_pat!($crate::cast::__private::DataType::Int32, $($data_type),+) => {
86                $m!($crate::types::Int32Type $(, $args)*)
87            }
88            $crate::repeat_pat!($crate::cast::__private::DataType::Int64, $($data_type),+) => {
89                $m!($crate::types::Int64Type $(, $args)*)
90            }
91            $crate::repeat_pat!($crate::cast::__private::DataType::UInt8, $($data_type),+) => {
92                $m!($crate::types::UInt8Type $(, $args)*)
93            }
94            $crate::repeat_pat!($crate::cast::__private::DataType::UInt16, $($data_type),+) => {
95                $m!($crate::types::UInt16Type $(, $args)*)
96            }
97            $crate::repeat_pat!($crate::cast::__private::DataType::UInt32, $($data_type),+) => {
98                $m!($crate::types::UInt32Type $(, $args)*)
99            }
100            $crate::repeat_pat!($crate::cast::__private::DataType::UInt64, $($data_type),+) => {
101                $m!($crate::types::UInt64Type $(, $args)*)
102            }
103            $($p $(if $pred)? => $fallback,)*
104        }
105    };
106}
107
108/// Given one or more expressions evaluating to an integer [`PrimitiveArray`] invokes the provided macro
109/// with the corresponding array, along with match statements for any non integer array types
110///
111/// ```
112/// # use arrow_array::{Array, downcast_integer_array, cast::as_string_array, cast::as_largestring_array};
113/// # use arrow_schema::DataType;
114///
115/// fn print_integer(array: &dyn Array) {
116///     downcast_integer_array!(
117///         array => {
118///             for v in array {
119///                 println!("{:?}", v);
120///             }
121///         }
122///         DataType::Utf8 => {
123///             for v in as_string_array(array) {
124///                 println!("{:?}", v);
125///             }
126///         }
127///         // You can also add a guard to the pattern
128///         DataType::LargeUtf8 if true => {
129///             for v in as_largestring_array(array) {
130///                 println!("{:?}", v);
131///             }
132///         }
133///         t => println!("Unsupported datatype {}", t)
134///     )
135/// }
136/// ```
137///
138/// [`DataType`]: arrow_schema::DataType
139#[macro_export]
140macro_rules! downcast_integer_array {
141    ($($values:ident),+ => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
142        $crate::downcast_integer!{
143            $($values.data_type()),+ => ($crate::downcast_primitive_array_helper, $($values),+, $e),
144            $($p $(if $pred)? => $fallback,)*
145        }
146    };
147    // Turn $e into a block.
148    ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
149        $crate::downcast_integer_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
150    };
151    // Remove $values parentheses.
152    (($($values:ident),+) => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
153        $crate::downcast_integer_array!($($values),+ => $e $($p $(if $pred)? => $fallback,)*)
154    };
155    // Turn $e into a block & remove $values parentheses.
156    (($($values:ident),+) => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
157        $crate::downcast_integer_array!($($values),+ => {$e} $($p $(if $pred)? => $fallback,)*)
158    };
159}
160
161/// Given one or more expressions evaluating to an integer [`DataType`] invokes the provided macro
162/// `m` with the corresponding integer [`RunEndIndexType`], followed by any additional arguments
163///
164/// ```
165/// # use std::sync::Arc;
166/// # use arrow_array::{downcast_primitive, ArrowPrimitiveType, downcast_run_end_index};
167/// # use arrow_schema::{DataType, Field};
168///
169/// macro_rules! run_end_size_helper {
170///   ($t:ty, $o:ty) => {
171///       std::mem::size_of::<<$t as ArrowPrimitiveType>::Native>() as $o
172///   };
173/// }
174///
175/// fn run_end_index_size(t: &DataType) -> u8 {
176///     match t {
177///         DataType::RunEndEncoded(k, _) => downcast_run_end_index! {
178///             k.data_type() => (run_end_size_helper, u8),
179///             _ => unreachable!(),
180///         },
181///         // You can also add a guard to the pattern
182///         DataType::LargeUtf8 if true => u8::MAX,
183///         _ => u8::MAX,
184///     }
185/// }
186///
187/// assert_eq!(run_end_index_size(&DataType::RunEndEncoded(Arc::new(Field::new("a", DataType::Int32, false)), Arc::new(Field::new("b", DataType::Utf8, true)))), 4);
188/// assert_eq!(run_end_index_size(&DataType::RunEndEncoded(Arc::new(Field::new("a", DataType::Int64, false)), Arc::new(Field::new("b", DataType::Utf8, true)))), 8);
189/// assert_eq!(run_end_index_size(&DataType::RunEndEncoded(Arc::new(Field::new("a", DataType::Int16, false)), Arc::new(Field::new("b", DataType::Utf8, true)))), 2);
190/// ```
191///
192/// [`DataType`]: arrow_schema::DataType
193#[macro_export]
194macro_rules! downcast_run_end_index {
195    ($($data_type:expr),+ => ($m:path $(, $args:tt)*), $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
196        match ($($data_type),+) {
197            $crate::repeat_pat!($crate::cast::__private::DataType::Int16, $($data_type),+) => {
198                $m!($crate::types::Int16Type $(, $args)*)
199            }
200            $crate::repeat_pat!($crate::cast::__private::DataType::Int32, $($data_type),+) => {
201                $m!($crate::types::Int32Type $(, $args)*)
202            }
203            $crate::repeat_pat!($crate::cast::__private::DataType::Int64, $($data_type),+) => {
204                $m!($crate::types::Int64Type $(, $args)*)
205            }
206            $($p $(if $pred)? => $fallback,)*
207        }
208    };
209}
210
211/// Given one or more expressions evaluating to primitive [`DataType`] invokes the provided macro
212/// `m` with the corresponding [`ArrowPrimitiveType`], followed by any additional arguments
213///
214/// ```
215/// # use arrow_array::{downcast_temporal, ArrowPrimitiveType};
216/// # use arrow_schema::DataType;
217///
218/// macro_rules! temporal_size_helper {
219///   ($t:ty, $o:ty) => {
220///       std::mem::size_of::<<$t as ArrowPrimitiveType>::Native>() as $o
221///   };
222/// }
223///
224/// fn temporal_size(t: &DataType) -> u8 {
225///     downcast_temporal! {
226///         t => (temporal_size_helper, u8),
227///         // You can also add a guard to the pattern
228///         DataType::LargeUtf8 if true => u8::MAX,
229///         _ => u8::MAX
230///     }
231/// }
232///
233/// assert_eq!(temporal_size(&DataType::Date32), 4);
234/// assert_eq!(temporal_size(&DataType::Date64), 8);
235/// ```
236///
237/// [`DataType`]: arrow_schema::DataType
238#[macro_export]
239macro_rules! downcast_temporal {
240    ($($data_type:expr),+ => ($m:path $(, $args:tt)*), $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
241        match ($($data_type),+) {
242            $crate::repeat_pat!($crate::cast::__private::DataType::Time32($crate::cast::__private::TimeUnit::Second), $($data_type),+) => {
243                $m!($crate::types::Time32SecondType $(, $args)*)
244            }
245            $crate::repeat_pat!($crate::cast::__private::DataType::Time32($crate::cast::__private::TimeUnit::Millisecond), $($data_type),+) => {
246                $m!($crate::types::Time32MillisecondType $(, $args)*)
247            }
248            $crate::repeat_pat!($crate::cast::__private::DataType::Time64($crate::cast::__private::TimeUnit::Microsecond), $($data_type),+) => {
249                $m!($crate::types::Time64MicrosecondType $(, $args)*)
250            }
251            $crate::repeat_pat!($crate::cast::__private::DataType::Time64($crate::cast::__private::TimeUnit::Nanosecond), $($data_type),+) => {
252                $m!($crate::types::Time64NanosecondType $(, $args)*)
253            }
254            $crate::repeat_pat!($crate::cast::__private::DataType::Date32, $($data_type),+) => {
255                $m!($crate::types::Date32Type $(, $args)*)
256            }
257            $crate::repeat_pat!($crate::cast::__private::DataType::Date64, $($data_type),+) => {
258                $m!($crate::types::Date64Type $(, $args)*)
259            }
260            $crate::repeat_pat!($crate::cast::__private::DataType::Timestamp($crate::cast::__private::TimeUnit::Second, _), $($data_type),+) => {
261                $m!($crate::types::TimestampSecondType $(, $args)*)
262            }
263            $crate::repeat_pat!($crate::cast::__private::DataType::Timestamp($crate::cast::__private::TimeUnit::Millisecond, _), $($data_type),+) => {
264                $m!($crate::types::TimestampMillisecondType $(, $args)*)
265            }
266            $crate::repeat_pat!($crate::cast::__private::DataType::Timestamp($crate::cast::__private::TimeUnit::Microsecond, _), $($data_type),+) => {
267                $m!($crate::types::TimestampMicrosecondType $(, $args)*)
268            }
269            $crate::repeat_pat!($crate::cast::__private::DataType::Timestamp($crate::cast::__private::TimeUnit::Nanosecond, _), $($data_type),+) => {
270                $m!($crate::types::TimestampNanosecondType $(, $args)*)
271            }
272            $($p $(if $pred)? => $fallback,)*
273        }
274    };
275}
276
277/// Downcast an [`Array`] to a temporal [`PrimitiveArray`] based on its [`DataType`]
278/// accepts a number of subsequent patterns to match the data type
279///
280/// ```
281/// # use arrow_array::{Array, downcast_temporal_array, cast::as_string_array, cast::as_largestring_array};
282/// # use arrow_schema::DataType;
283///
284/// fn print_temporal(array: &dyn Array) {
285///     downcast_temporal_array!(
286///         array => {
287///             for v in array {
288///                 println!("{:?}", v);
289///             }
290///         }
291///         DataType::Utf8 => {
292///             for v in as_string_array(array) {
293///                 println!("{:?}", v);
294///             }
295///         }
296///         // You can also add a guard to the pattern
297///         DataType::LargeUtf8 if true => {
298///             for v in as_largestring_array(array) {
299///                 println!("{:?}", v);
300///             }
301///         }
302///         t => println!("Unsupported datatype {}", t)
303///     )
304/// }
305/// ```
306///
307/// [`DataType`]: arrow_schema::DataType
308#[macro_export]
309macro_rules! downcast_temporal_array {
310    ($($values:ident),+ => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
311        $crate::downcast_temporal!{
312            $($values.data_type()),+ => ($crate::downcast_primitive_array_helper, $($values),+, $e),
313            $($p $(if $pred)? => $fallback,)*
314        }
315    };
316    // Turn $e into a block.
317    ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
318        $crate::downcast_temporal_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
319    };
320    // Remove $values parentheses.
321    (($($values:ident),+) => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
322        $crate::downcast_temporal_array!($($values),+ => $e $($p $(if $pred)? => $fallback,)*)
323    };
324    // Turn $e into a block & remove $values parentheses.
325    (($($values:ident),+) => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
326        $crate::downcast_temporal_array!($($values),+ => {$e} $($p $(if $pred)? => $fallback,)*)
327    };
328}
329
330/// Given one or more expressions evaluating to primitive [`DataType`] invokes the provided macro
331/// `m` with the corresponding [`ArrowPrimitiveType`], followed by any additional arguments
332///
333/// ```
334/// # use arrow_array::{downcast_primitive, ArrowPrimitiveType};
335/// # use arrow_schema::DataType;
336///
337/// macro_rules! primitive_size_helper {
338///   ($t:ty, $o:ty) => {
339///       std::mem::size_of::<<$t as ArrowPrimitiveType>::Native>() as $o
340///   };
341/// }
342///
343/// fn primitive_size(t: &DataType) -> u8 {
344///     downcast_primitive! {
345///         t => (primitive_size_helper, u8),
346///         // You can also add a guard to the pattern
347///         DataType::LargeUtf8 if true => u8::MAX,
348///         _ => u8::MAX
349///     }
350/// }
351///
352/// assert_eq!(primitive_size(&DataType::Int32), 4);
353/// assert_eq!(primitive_size(&DataType::Int64), 8);
354/// assert_eq!(primitive_size(&DataType::Float16), 2);
355/// assert_eq!(primitive_size(&DataType::Decimal128(38, 10)), 16);
356/// assert_eq!(primitive_size(&DataType::Decimal256(76, 20)), 32);
357/// ```
358///
359/// [`DataType`]: arrow_schema::DataType
360#[macro_export]
361macro_rules! downcast_primitive {
362    ($($data_type:expr),+ => ($m:path $(, $args:tt)*), $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
363        $crate::downcast_integer! {
364            $($data_type),+ => ($m $(, $args)*),
365            $crate::repeat_pat!($crate::cast::__private::DataType::Float16, $($data_type),+) => {
366                $m!($crate::types::Float16Type $(, $args)*)
367            }
368            $crate::repeat_pat!($crate::cast::__private::DataType::Float32, $($data_type),+) => {
369                $m!($crate::types::Float32Type $(, $args)*)
370            }
371            $crate::repeat_pat!($crate::cast::__private::DataType::Float64, $($data_type),+) => {
372                $m!($crate::types::Float64Type $(, $args)*)
373            }
374            $crate::repeat_pat!($crate::cast::__private::DataType::Decimal32(_, _), $($data_type),+) => {
375                $m!($crate::types::Decimal32Type $(, $args)*)
376            }
377            $crate::repeat_pat!($crate::cast::__private::DataType::Decimal64(_, _), $($data_type),+) => {
378                $m!($crate::types::Decimal64Type $(, $args)*)
379            }
380            $crate::repeat_pat!($crate::cast::__private::DataType::Decimal128(_, _), $($data_type),+) => {
381                $m!($crate::types::Decimal128Type $(, $args)*)
382            }
383            $crate::repeat_pat!($crate::cast::__private::DataType::Decimal256(_, _), $($data_type),+) => {
384                $m!($crate::types::Decimal256Type $(, $args)*)
385            }
386            $crate::repeat_pat!($crate::cast::__private::DataType::Interval($crate::cast::__private::IntervalUnit::YearMonth), $($data_type),+) => {
387                $m!($crate::types::IntervalYearMonthType $(, $args)*)
388            }
389            $crate::repeat_pat!($crate::cast::__private::DataType::Interval($crate::cast::__private::IntervalUnit::DayTime), $($data_type),+) => {
390                $m!($crate::types::IntervalDayTimeType $(, $args)*)
391            }
392            $crate::repeat_pat!($crate::cast::__private::DataType::Interval($crate::cast::__private::IntervalUnit::MonthDayNano), $($data_type),+) => {
393                $m!($crate::types::IntervalMonthDayNanoType $(, $args)*)
394            }
395            $crate::repeat_pat!($crate::cast::__private::DataType::Duration($crate::cast::__private::TimeUnit::Second), $($data_type),+) => {
396                $m!($crate::types::DurationSecondType $(, $args)*)
397            }
398            $crate::repeat_pat!($crate::cast::__private::DataType::Duration($crate::cast::__private::TimeUnit::Millisecond), $($data_type),+) => {
399                $m!($crate::types::DurationMillisecondType $(, $args)*)
400            }
401            $crate::repeat_pat!($crate::cast::__private::DataType::Duration($crate::cast::__private::TimeUnit::Microsecond), $($data_type),+) => {
402                $m!($crate::types::DurationMicrosecondType $(, $args)*)
403            }
404            $crate::repeat_pat!($crate::cast::__private::DataType::Duration($crate::cast::__private::TimeUnit::Nanosecond), $($data_type),+) => {
405                $m!($crate::types::DurationNanosecondType $(, $args)*)
406            }
407            _ => {
408                $crate::downcast_temporal! {
409                    $($data_type),+ => ($m $(, $args)*),
410                    $($p $(if $pred)? => $fallback,)*
411                }
412            }
413        }
414    };
415}
416
417#[macro_export]
418#[doc(hidden)]
419macro_rules! downcast_primitive_array_helper {
420    ($t:ty, $($values:ident),+, $e:block) => {{
421        $(let $values = $crate::cast::as_primitive_array::<$t>($values);)+
422        $e
423    }};
424}
425
426/// Downcast an [`Array`] to a [`PrimitiveArray`] based on its [`DataType`]
427/// accepts a number of subsequent patterns to match the data type
428///
429/// ```
430/// # use arrow_array::{Array, downcast_primitive_array, cast::as_string_array, cast::as_largestring_array};
431/// # use arrow_schema::DataType;
432///
433/// fn print_primitive(array: &dyn Array) {
434///     downcast_primitive_array!(
435///         array => {
436///             for v in array {
437///                 println!("{:?}", v);
438///             }
439///         }
440///         DataType::Utf8 => {
441///             for v in as_string_array(array) {
442///                 println!("{:?}", v);
443///             }
444///         }
445///         // You can also add a guard to the pattern
446///         DataType::LargeUtf8 if true => {
447///             for v in as_largestring_array(array) {
448///                 println!("{:?}", v);
449///             }
450///         }
451///         t => println!("Unsupported datatype {}", t)
452///     )
453/// }
454/// ```
455///
456/// [`DataType`]: arrow_schema::DataType
457#[macro_export]
458macro_rules! downcast_primitive_array {
459    ($($values:ident),+ => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
460        $crate::downcast_primitive!{
461            $($values.data_type()),+ => ($crate::downcast_primitive_array_helper, $($values),+, $e),
462            $($p $(if $pred)? => $fallback,)*
463        }
464    };
465    // Turn $e into a block.
466    ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
467        $crate::downcast_primitive_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
468    };
469    // Remove $values parentheses.
470    (($($values:ident),+) => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
471        $crate::downcast_primitive_array!($($values),+ => $e $($p $(if $pred)? => $fallback,)*)
472    };
473    // Turn $e into a block & remove $values parentheses.
474    (($($values:ident),+) => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
475        $crate::downcast_primitive_array!($($values),+ => {$e} $($p $(if $pred)? => $fallback,)*)
476    };
477}
478
479/// Force downcast of an [`Array`], such as an [`ArrayRef`], to
480/// [`PrimitiveArray<T>`], panic'ing on failure.
481///
482/// # Example
483///
484/// ```
485/// # use std::sync::Arc;
486/// # use arrow_array::{ArrayRef, Int32Array};
487/// # use arrow_array::cast::as_primitive_array;
488/// # use arrow_array::types::Int32Type;
489///
490/// let arr: ArrayRef = Arc::new(Int32Array::from(vec![Some(1)]));
491///
492/// // Downcast an `ArrayRef` to Int32Array / PrimitiveArray<Int32>:
493/// let primitive_array: &Int32Array = as_primitive_array(&arr);
494///
495/// // Equivalently:
496/// let primitive_array = as_primitive_array::<Int32Type>(&arr);
497///
498/// // This is the equivalent of:
499/// let primitive_array = arr
500///     .as_any()
501///     .downcast_ref::<Int32Array>()
502///     .unwrap();
503/// ```
504pub fn as_primitive_array<T>(arr: &dyn Array) -> &PrimitiveArray<T>
505where
506    T: ArrowPrimitiveType,
507{
508    arr.as_any()
509        .downcast_ref::<PrimitiveArray<T>>()
510        .expect("Unable to downcast to primitive array")
511}
512
513#[macro_export]
514#[doc(hidden)]
515macro_rules! downcast_dictionary_array_helper {
516    ($t:ty, $($values:ident),+, $e:block) => {{
517        $(let $values = $crate::cast::as_dictionary_array::<$t>($values);)+
518        $e
519    }};
520}
521
522/// Downcast an [`Array`] to a [`DictionaryArray`] based on its [`DataType`], accepts
523/// a number of subsequent patterns to match the data type
524///
525/// ```
526/// # use arrow_array::{Array, StringArray, downcast_dictionary_array, cast::as_string_array, cast::as_largestring_array};
527/// # use arrow_schema::DataType;
528///
529/// fn print_strings(array: &dyn Array) {
530///     downcast_dictionary_array!(
531///         array => match array.values().data_type() {
532///             DataType::Utf8 => {
533///                 for v in array.downcast_dict::<StringArray>().unwrap() {
534///                     println!("{:?}", v);
535///                 }
536///             }
537///             t => println!("Unsupported dictionary value type {}", t),
538///         },
539///         DataType::Utf8 => {
540///             for v in as_string_array(array) {
541///                 println!("{:?}", v);
542///             }
543///         }
544///         // You can also add a guard to the pattern
545///         DataType::LargeUtf8 if true => {
546///             for v in as_largestring_array(array) {
547///                 println!("{:?}", v);
548///             }
549///         }
550///         t => println!("Unsupported datatype {}", t)
551///     )
552/// }
553/// ```
554///
555/// [`DataType`]: arrow_schema::DataType
556#[macro_export]
557macro_rules! downcast_dictionary_array {
558    ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
559        downcast_dictionary_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
560    };
561
562    ($values:ident => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
563        match $values.data_type() {
564            $crate::cast::__private::DataType::Dictionary(k, _) => {
565                $crate::downcast_integer! {
566                    k.as_ref() => ($crate::downcast_dictionary_array_helper, $values, $e),
567                    k => unreachable!("unsupported dictionary key type: {}", k)
568                }
569            }
570            $($p $(if $pred)? => $fallback,)*
571        }
572    }
573}
574
575/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
576/// [`DictionaryArray<T>`], panic'ing on failure.
577///
578/// # Example
579///
580/// ```
581/// # use arrow_array::{ArrayRef, DictionaryArray};
582/// # use arrow_array::cast::as_dictionary_array;
583/// # use arrow_array::types::Int32Type;
584///
585/// let arr: DictionaryArray<Int32Type> = vec![Some("foo")].into_iter().collect();
586/// let arr: ArrayRef = std::sync::Arc::new(arr);
587/// let dict_array: &DictionaryArray<Int32Type> = as_dictionary_array::<Int32Type>(&arr);
588/// ```
589pub fn as_dictionary_array<T>(arr: &dyn Array) -> &DictionaryArray<T>
590where
591    T: ArrowDictionaryKeyType,
592{
593    arr.as_any()
594        .downcast_ref::<DictionaryArray<T>>()
595        .expect("Unable to downcast to dictionary array")
596}
597
598/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
599/// [`RunArray<T>`], panic'ing on failure.
600///
601/// # Example
602///
603/// ```
604/// # use arrow_array::{ArrayRef, RunArray};
605/// # use arrow_array::cast::as_run_array;
606/// # use arrow_array::types::Int32Type;
607///
608/// let arr: RunArray<Int32Type> = vec![Some("foo")].into_iter().collect();
609/// let arr: ArrayRef = std::sync::Arc::new(arr);
610/// let run_array: &RunArray<Int32Type> = as_run_array::<Int32Type>(&arr);
611/// ```
612pub fn as_run_array<T>(arr: &dyn Array) -> &RunArray<T>
613where
614    T: RunEndIndexType,
615{
616    arr.as_any()
617        .downcast_ref::<RunArray<T>>()
618        .expect("Unable to downcast to run array")
619}
620
621#[macro_export]
622#[doc(hidden)]
623macro_rules! downcast_run_array_helper {
624    ($t:ty, $($values:ident),+, $e:block) => {{
625        $(let $values = $crate::cast::as_run_array::<$t>($values);)+
626        $e
627    }};
628}
629
630/// Downcast an [`Array`] to a [`RunArray`] based on its [`DataType`], accepts
631/// a number of subsequent patterns to match the data type
632///
633/// ```
634/// # use arrow_array::{Array, StringArray, downcast_run_array, cast::as_string_array, cast::as_largestring_array};
635/// # use arrow_schema::DataType;
636///
637/// fn print_strings(array: &dyn Array) {
638///     downcast_run_array!(
639///         array => match array.values().data_type() {
640///             DataType::Utf8 => {
641///                 for v in array.downcast::<StringArray>().unwrap() {
642///                     println!("{:?}", v);
643///                 }
644///             }
645///             t => println!("Unsupported run array value type {}", t),
646///         },
647///         DataType::Utf8 => {
648///             for v in as_string_array(array) {
649///                 println!("{:?}", v);
650///             }
651///         }
652///         // You can also add a guard to the pattern
653///         DataType::LargeUtf8 if true => {
654///             for v in as_largestring_array(array) {
655///                 println!("{:?}", v);
656///             }
657///         }
658///         t => println!("Unsupported datatype {}", t)
659///     )
660/// }
661/// ```
662///
663/// [`DataType`]: arrow_schema::DataType
664#[macro_export]
665macro_rules! downcast_run_array {
666    ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
667        downcast_run_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
668    };
669
670    ($values:ident => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
671        match $values.data_type() {
672            $crate::cast::__private::DataType::RunEndEncoded(k, _) => {
673                $crate::downcast_run_end_index! {
674                    k.data_type() => ($crate::downcast_run_array_helper, $values, $e),
675                    k => unreachable!("unsupported run end index type: {}", k)
676                }
677            }
678            $($p $(if $pred)? => $fallback,)*
679        }
680    }
681}
682
683/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
684/// [`GenericListArray<T>`], panicking on failure.
685pub fn as_generic_list_array<S: OffsetSizeTrait>(arr: &dyn Array) -> &GenericListArray<S> {
686    arr.as_any()
687        .downcast_ref::<GenericListArray<S>>()
688        .expect("Unable to downcast to list array")
689}
690
691/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
692/// [`ListArray`], panicking on failure.
693#[inline]
694pub fn as_list_array(arr: &dyn Array) -> &ListArray {
695    as_generic_list_array::<i32>(arr)
696}
697
698/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
699/// [`FixedSizeListArray`], panicking on failure.
700#[inline]
701pub fn as_fixed_size_list_array(arr: &dyn Array) -> &FixedSizeListArray {
702    arr.as_any()
703        .downcast_ref::<FixedSizeListArray>()
704        .expect("Unable to downcast to fixed size list array")
705}
706
707/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
708/// [`LargeListArray`], panicking on failure.
709#[inline]
710pub fn as_large_list_array(arr: &dyn Array) -> &LargeListArray {
711    as_generic_list_array::<i64>(arr)
712}
713
714/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
715/// [`GenericBinaryArray<S>`], panicking on failure.
716#[inline]
717pub fn as_generic_binary_array<S: OffsetSizeTrait>(arr: &dyn Array) -> &GenericBinaryArray<S> {
718    arr.as_any()
719        .downcast_ref::<GenericBinaryArray<S>>()
720        .expect("Unable to downcast to binary array")
721}
722
723/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
724/// [`StringArray`], panicking on failure.
725///
726/// # Example
727///
728/// ```
729/// # use std::sync::Arc;
730/// # use arrow_array::cast::as_string_array;
731/// # use arrow_array::{ArrayRef, StringArray};
732///
733/// let arr: ArrayRef = Arc::new(StringArray::from_iter(vec![Some("foo")]));
734/// let string_array = as_string_array(&arr);
735/// ```
736pub fn as_string_array(arr: &dyn Array) -> &StringArray {
737    arr.as_any()
738        .downcast_ref::<StringArray>()
739        .expect("Unable to downcast to StringArray")
740}
741
742/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
743/// [`BooleanArray`], panicking on failure.
744///
745/// # Example
746///
747/// ```
748/// # use std::sync::Arc;
749/// # use arrow_array::{ArrayRef, BooleanArray};
750/// # use arrow_array::cast::as_boolean_array;
751///
752/// let arr: ArrayRef = Arc::new(BooleanArray::from_iter(vec![Some(true)]));
753/// let boolean_array = as_boolean_array(&arr);
754/// ```
755pub fn as_boolean_array(arr: &dyn Array) -> &BooleanArray {
756    arr.as_any()
757        .downcast_ref::<BooleanArray>()
758        .expect("Unable to downcast to BooleanArray")
759}
760
761macro_rules! array_downcast_fn {
762    ($name: ident, $arrty: ty, $arrty_str:expr) => {
763        #[doc = "Force downcast of an [`Array`], such as an [`ArrayRef`] to "]
764        #[doc = $arrty_str]
765        pub fn $name(arr: &dyn Array) -> &$arrty {
766            arr.as_any().downcast_ref::<$arrty>().expect(concat!(
767                "Unable to downcast to typed array through ",
768                stringify!($name)
769            ))
770        }
771    };
772
773    // use recursive macro to generate dynamic doc string for a given array type
774    ($name: ident, $arrty: ty) => {
775        array_downcast_fn!(
776            $name,
777            $arrty,
778            concat!("[`", stringify!($arrty), "`], panicking on failure.")
779        );
780    };
781}
782
783array_downcast_fn!(as_largestring_array, LargeStringArray);
784array_downcast_fn!(as_null_array, NullArray);
785array_downcast_fn!(as_struct_array, StructArray);
786array_downcast_fn!(as_union_array, UnionArray);
787array_downcast_fn!(as_map_array, MapArray);
788
789/// Downcasts a `dyn Array` to a concrete type
790///
791/// ```
792/// # use arrow_array::{BooleanArray, Int32Array, RecordBatch, StringArray};
793/// # use arrow_array::cast::downcast_array;
794/// struct ConcreteBatch {
795///     col1: Int32Array,
796///     col2: BooleanArray,
797///     col3: StringArray,
798/// }
799///
800/// impl ConcreteBatch {
801///     fn new(batch: &RecordBatch) -> Self {
802///         Self {
803///             col1: downcast_array(batch.column(0).as_ref()),
804///             col2: downcast_array(batch.column(1).as_ref()),
805///             col3: downcast_array(batch.column(2).as_ref()),
806///         }
807///     }
808/// }
809/// ```
810///
811/// # Panics
812///
813/// Panics if array is not of the correct data type
814pub fn downcast_array<T>(array: &dyn Array) -> T
815where
816    T: From<ArrayData>,
817{
818    T::from(array.to_data())
819}
820
821mod private {
822    pub trait Sealed {}
823}
824
825/// An extension trait for `dyn Array` that provides ergonomic downcasting
826///
827/// ```
828/// # use std::sync::Arc;
829/// # use arrow_array::{ArrayRef, Int32Array};
830/// # use arrow_array::cast::AsArray;
831/// # use arrow_array::types::Int32Type;
832/// let col = Arc::new(Int32Array::from(vec![1, 2, 3])) as ArrayRef;
833/// assert_eq!(col.as_primitive::<Int32Type>().values(), &[1, 2, 3]);
834/// ```
835pub trait AsArray: private::Sealed {
836    /// Downcast this to a [`BooleanArray`] returning `None` if not possible
837    fn as_boolean_opt(&self) -> Option<&BooleanArray>;
838
839    /// Downcast this to a [`BooleanArray`] panicking if not possible
840    fn as_boolean(&self) -> &BooleanArray {
841        self.as_boolean_opt().expect("boolean array")
842    }
843
844    /// Downcast this to a [`PrimitiveArray`] returning `None` if not possible
845    fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>>;
846
847    /// Downcast this to a [`PrimitiveArray`] panicking if not possible
848    fn as_primitive<T: ArrowPrimitiveType>(&self) -> &PrimitiveArray<T> {
849        self.as_primitive_opt().expect("primitive array")
850    }
851
852    /// Downcast this to a [`GenericByteArray`] returning `None` if not possible
853    fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>>;
854
855    /// Downcast this to a [`GenericByteArray`] panicking if not possible
856    fn as_bytes<T: ByteArrayType>(&self) -> &GenericByteArray<T> {
857        self.as_bytes_opt().expect("byte array")
858    }
859
860    /// Downcast this to a [`GenericStringArray`] returning `None` if not possible
861    fn as_string_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericStringArray<O>> {
862        self.as_bytes_opt()
863    }
864
865    /// Downcast this to a [`GenericStringArray`] panicking if not possible
866    fn as_string<O: OffsetSizeTrait>(&self) -> &GenericStringArray<O> {
867        self.as_bytes_opt().expect("string array")
868    }
869
870    /// Downcast this to a [`GenericBinaryArray`] returning `None` if not possible
871    fn as_binary_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericBinaryArray<O>> {
872        self.as_bytes_opt()
873    }
874
875    /// Downcast this to a [`GenericBinaryArray`] panicking if not possible
876    fn as_binary<O: OffsetSizeTrait>(&self) -> &GenericBinaryArray<O> {
877        self.as_bytes_opt().expect("binary array")
878    }
879
880    /// Downcast this to a [`StringViewArray`] returning `None` if not possible
881    fn as_string_view_opt(&self) -> Option<&StringViewArray> {
882        self.as_byte_view_opt()
883    }
884
885    /// Downcast this to a [`StringViewArray`] panicking if not possible
886    fn as_string_view(&self) -> &StringViewArray {
887        self.as_byte_view_opt().expect("string view array")
888    }
889
890    /// Downcast this to a [`BinaryViewArray`] returning `None` if not possible
891    fn as_binary_view_opt(&self) -> Option<&BinaryViewArray> {
892        self.as_byte_view_opt()
893    }
894
895    /// Downcast this to a [`BinaryViewArray`] panicking if not possible
896    fn as_binary_view(&self) -> &BinaryViewArray {
897        self.as_byte_view_opt().expect("binary view array")
898    }
899
900    /// Downcast this to a [`GenericByteViewArray`] returning `None` if not possible
901    fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>>;
902
903    /// Downcast this to a [`GenericByteViewArray`] panicking if not possible
904    fn as_byte_view<T: ByteViewType>(&self) -> &GenericByteViewArray<T> {
905        self.as_byte_view_opt().expect("byte view array")
906    }
907
908    /// Downcast this to a [`StructArray`] returning `None` if not possible
909    fn as_struct_opt(&self) -> Option<&StructArray>;
910
911    /// Downcast this to a [`StructArray`] panicking if not possible
912    fn as_struct(&self) -> &StructArray {
913        self.as_struct_opt().expect("struct array")
914    }
915
916    /// Downcast this to a [`UnionArray`] returning `None` if not possible
917    fn as_union_opt(&self) -> Option<&UnionArray>;
918
919    /// Downcast this to a [`UnionArray`] panicking if not possible
920    fn as_union(&self) -> &UnionArray {
921        self.as_union_opt().expect("union array")
922    }
923
924    /// Downcast this to a [`GenericListArray`] returning `None` if not possible
925    fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>>;
926
927    /// Downcast this to a [`GenericListArray`] panicking if not possible
928    fn as_list<O: OffsetSizeTrait>(&self) -> &GenericListArray<O> {
929        self.as_list_opt().expect("list array")
930    }
931
932    /// Downcast this to a [`GenericListViewArray`] returning `None` if not possible
933    fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>>;
934
935    /// Downcast this to a [`GenericListViewArray`] panicking if not possible
936    fn as_list_view<O: OffsetSizeTrait>(&self) -> &GenericListViewArray<O> {
937        self.as_list_view_opt().expect("list view array")
938    }
939
940    /// Downcast this to a [`FixedSizeBinaryArray`] returning `None` if not possible
941    fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray>;
942
943    /// Downcast this to a [`FixedSizeBinaryArray`] panicking if not possible
944    fn as_fixed_size_binary(&self) -> &FixedSizeBinaryArray {
945        self.as_fixed_size_binary_opt()
946            .expect("fixed size binary array")
947    }
948
949    /// Downcast this to a [`FixedSizeListArray`] returning `None` if not possible
950    fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray>;
951
952    /// Downcast this to a [`FixedSizeListArray`] panicking if not possible
953    fn as_fixed_size_list(&self) -> &FixedSizeListArray {
954        self.as_fixed_size_list_opt()
955            .expect("fixed size list array")
956    }
957
958    /// Downcast this to a [`MapArray`] returning `None` if not possible
959    fn as_map_opt(&self) -> Option<&MapArray>;
960
961    /// Downcast this to a [`MapArray`] panicking if not possible
962    fn as_map(&self) -> &MapArray {
963        self.as_map_opt().expect("map array")
964    }
965
966    /// Downcast this to a [`DictionaryArray`] returning `None` if not possible
967    fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>>;
968
969    /// Downcast this to a [`DictionaryArray`] panicking if not possible
970    fn as_dictionary<K: ArrowDictionaryKeyType>(&self) -> &DictionaryArray<K> {
971        self.as_dictionary_opt().expect("dictionary array")
972    }
973
974    /// Downcast this to a [`RunArray`] returning `None` if not possible
975    fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>>;
976
977    /// Downcast this to a [`RunArray`] panicking if not possible
978    fn as_run<K: RunEndIndexType>(&self) -> &RunArray<K> {
979        self.as_run_opt().expect("run array")
980    }
981
982    /// Downcasts this to a [`AnyDictionaryArray`] returning `None` if not possible
983    fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray>;
984
985    /// Downcasts this to a [`AnyDictionaryArray`] panicking if not possible
986    fn as_any_dictionary(&self) -> &dyn AnyDictionaryArray {
987        self.as_any_dictionary_opt().expect("any dictionary array")
988    }
989}
990
991impl private::Sealed for dyn Array + '_ {}
992impl AsArray for dyn Array + '_ {
993    fn as_boolean_opt(&self) -> Option<&BooleanArray> {
994        self.as_any().downcast_ref()
995    }
996
997    fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>> {
998        self.as_any().downcast_ref()
999    }
1000
1001    fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>> {
1002        self.as_any().downcast_ref()
1003    }
1004
1005    fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>> {
1006        self.as_any().downcast_ref()
1007    }
1008
1009    fn as_struct_opt(&self) -> Option<&StructArray> {
1010        self.as_any().downcast_ref()
1011    }
1012
1013    fn as_union_opt(&self) -> Option<&UnionArray> {
1014        self.as_any().downcast_ref()
1015    }
1016
1017    fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>> {
1018        self.as_any().downcast_ref()
1019    }
1020
1021    fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>> {
1022        self.as_any().downcast_ref()
1023    }
1024
1025    fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray> {
1026        self.as_any().downcast_ref()
1027    }
1028
1029    fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray> {
1030        self.as_any().downcast_ref()
1031    }
1032
1033    fn as_map_opt(&self) -> Option<&MapArray> {
1034        self.as_any().downcast_ref()
1035    }
1036
1037    fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>> {
1038        self.as_any().downcast_ref()
1039    }
1040
1041    fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>> {
1042        self.as_any().downcast_ref()
1043    }
1044
1045    fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray> {
1046        let array = self;
1047        downcast_dictionary_array! {
1048            array => Some(array),
1049            _ => None
1050        }
1051    }
1052}
1053
1054impl private::Sealed for ArrayRef {}
1055impl AsArray for ArrayRef {
1056    fn as_boolean_opt(&self) -> Option<&BooleanArray> {
1057        self.as_ref().as_boolean_opt()
1058    }
1059
1060    fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>> {
1061        self.as_ref().as_primitive_opt()
1062    }
1063
1064    fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>> {
1065        self.as_ref().as_bytes_opt()
1066    }
1067
1068    fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>> {
1069        self.as_ref().as_byte_view_opt()
1070    }
1071
1072    fn as_struct_opt(&self) -> Option<&StructArray> {
1073        self.as_ref().as_struct_opt()
1074    }
1075
1076    fn as_union_opt(&self) -> Option<&UnionArray> {
1077        self.as_any().downcast_ref()
1078    }
1079
1080    fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>> {
1081        self.as_ref().as_list_opt()
1082    }
1083
1084    fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>> {
1085        self.as_ref().as_list_view_opt()
1086    }
1087
1088    fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray> {
1089        self.as_ref().as_fixed_size_binary_opt()
1090    }
1091
1092    fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray> {
1093        self.as_ref().as_fixed_size_list_opt()
1094    }
1095
1096    fn as_map_opt(&self) -> Option<&MapArray> {
1097        self.as_any().downcast_ref()
1098    }
1099
1100    fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>> {
1101        self.as_ref().as_dictionary_opt()
1102    }
1103
1104    fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray> {
1105        self.as_ref().as_any_dictionary_opt()
1106    }
1107
1108    fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>> {
1109        self.as_ref().as_run_opt()
1110    }
1111
1112    fn as_string_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericStringArray<O>> {
1113        self.as_ref().as_string_opt()
1114    }
1115}
1116
1117#[cfg(test)]
1118mod tests {
1119    use super::*;
1120    use arrow_buffer::i256;
1121    use arrow_schema::DataType;
1122    use std::sync::Arc;
1123
1124    #[test]
1125    fn test_as_primitive_array_ref() {
1126        let array: Int32Array = vec![1, 2, 3].into_iter().map(Some).collect();
1127        assert!(!as_primitive_array::<Int32Type>(&array).is_empty());
1128
1129        // should also work when wrapped in an Arc
1130        let array: ArrayRef = Arc::new(array);
1131        assert!(!as_primitive_array::<Int32Type>(&array).is_empty());
1132    }
1133
1134    #[test]
1135    fn test_as_string_array_ref() {
1136        let array: StringArray = vec!["foo", "bar"].into_iter().map(Some).collect();
1137        assert!(!as_string_array(&array).is_empty());
1138
1139        // should also work when wrapped in an Arc
1140        let array: ArrayRef = Arc::new(array);
1141        assert!(!as_string_array(&array).is_empty())
1142    }
1143
1144    #[test]
1145    fn test_decimal32array() {
1146        let a = Decimal32Array::from_iter_values([1, 2, 4, 5]);
1147        assert!(!as_primitive_array::<Decimal32Type>(&a).is_empty());
1148    }
1149
1150    #[test]
1151    fn test_decimal64array() {
1152        let a = Decimal64Array::from_iter_values([1, 2, 4, 5]);
1153        assert!(!as_primitive_array::<Decimal64Type>(&a).is_empty());
1154    }
1155
1156    #[test]
1157    fn test_decimal128array() {
1158        let a = Decimal128Array::from_iter_values([1, 2, 4, 5]);
1159        assert!(!as_primitive_array::<Decimal128Type>(&a).is_empty());
1160    }
1161
1162    #[test]
1163    fn test_decimal256array() {
1164        let a = Decimal256Array::from_iter_values([1, 2, 4, 5].into_iter().map(i256::from_i128));
1165        assert!(!as_primitive_array::<Decimal256Type>(&a).is_empty());
1166    }
1167
1168    #[test]
1169    fn downcast_integer_array_should_match_only_integers() {
1170        let i32_array: ArrayRef = Arc::new(Int32Array::new_null(1));
1171        let i32_array_ref = &i32_array;
1172        downcast_integer_array!(
1173            i32_array_ref => {
1174                assert_eq!(i32_array_ref.null_count(), 1);
1175            },
1176            _ => panic!("unexpected data type")
1177        );
1178    }
1179
1180    #[test]
1181    fn downcast_integer_array_should_not_match_primitive_that_are_not_integers() {
1182        let array: ArrayRef = Arc::new(Float32Array::new_null(1));
1183        let array_ref = &array;
1184        downcast_integer_array!(
1185            array_ref => {
1186                panic!("unexpected data type {}", array_ref.data_type())
1187            },
1188            DataType::Float32 => {
1189                assert_eq!(array_ref.null_count(), 1);
1190            },
1191            _ => panic!("unexpected data type")
1192        );
1193    }
1194
1195    #[test]
1196    fn downcast_integer_array_should_not_match_non_primitive() {
1197        let array: ArrayRef = Arc::new(StringArray::new_null(1));
1198        let array_ref = &array;
1199        downcast_integer_array!(
1200            array_ref => {
1201                panic!("unexpected data type {}", array_ref.data_type())
1202            },
1203            DataType::Utf8 => {
1204                assert_eq!(array_ref.null_count(), 1);
1205            },
1206            _ => panic!("unexpected data type")
1207        );
1208    }
1209}