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