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>`].
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/// ```
504///
505/// # Panics
506///
507/// Panics if `arr` is not a [`PrimitiveArray<T>`]
508pub fn as_primitive_array<T>(arr: &dyn Array) -> &PrimitiveArray<T>
509where
510 T: ArrowPrimitiveType,
511{
512 arr.as_any()
513 .downcast_ref::<PrimitiveArray<T>>()
514 .expect("Unable to downcast to primitive array")
515}
516
517#[macro_export]
518#[doc(hidden)]
519macro_rules! downcast_dictionary_array_helper {
520 ($t:ty, $($values:ident),+, $e:block) => {{
521 $(let $values = $crate::cast::as_dictionary_array::<$t>($values);)+
522 $e
523 }};
524}
525
526/// Downcast an [`Array`] to a [`DictionaryArray`] based on its [`DataType`], accepts
527/// a number of subsequent patterns to match the data type
528///
529/// ```
530/// # use arrow_array::{Array, StringArray, downcast_dictionary_array, cast::as_string_array, cast::as_largestring_array};
531/// # use arrow_schema::DataType;
532///
533/// fn print_strings(array: &dyn Array) {
534/// downcast_dictionary_array!(
535/// array => match array.values().data_type() {
536/// DataType::Utf8 => {
537/// for v in array.downcast_dict::<StringArray>().unwrap() {
538/// println!("{:?}", v);
539/// }
540/// }
541/// t => println!("Unsupported dictionary value type {}", t),
542/// },
543/// DataType::Utf8 => {
544/// for v in as_string_array(array) {
545/// println!("{:?}", v);
546/// }
547/// }
548/// // You can also add a guard to the pattern
549/// DataType::LargeUtf8 if true => {
550/// for v in as_largestring_array(array) {
551/// println!("{:?}", v);
552/// }
553/// }
554/// t => println!("Unsupported datatype {}", t)
555/// )
556/// }
557/// ```
558///
559/// [`DataType`]: arrow_schema::DataType
560#[macro_export]
561macro_rules! downcast_dictionary_array {
562 ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
563 downcast_dictionary_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
564 };
565
566 ($values:ident => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
567 match $values.data_type() {
568 $crate::cast::__private::DataType::Dictionary(k, _) => {
569 $crate::downcast_integer! {
570 k.as_ref() => ($crate::downcast_dictionary_array_helper, $values, $e),
571 k => unreachable!("unsupported dictionary key type: {}", k)
572 }
573 }
574 $($p $(if $pred)? => $fallback,)*
575 }
576 }
577}
578
579/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
580/// [`DictionaryArray<T>`].
581///
582/// # Example
583///
584/// ```
585/// # use arrow_array::{ArrayRef, DictionaryArray};
586/// # use arrow_array::cast::as_dictionary_array;
587/// # use arrow_array::types::Int32Type;
588///
589/// let arr: DictionaryArray<Int32Type> = vec![Some("foo")].into_iter().collect();
590/// let arr: ArrayRef = std::sync::Arc::new(arr);
591/// let dict_array: &DictionaryArray<Int32Type> = as_dictionary_array::<Int32Type>(&arr);
592/// ```
593///
594/// # Panics
595///
596/// Panics if `arr` is not a [`DictionaryArray<T>`]
597pub fn as_dictionary_array<T>(arr: &dyn Array) -> &DictionaryArray<T>
598where
599 T: ArrowDictionaryKeyType,
600{
601 arr.as_any()
602 .downcast_ref::<DictionaryArray<T>>()
603 .expect("Unable to downcast to dictionary array")
604}
605
606/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
607/// [`RunArray<T>`].
608///
609/// # Example
610///
611/// ```
612/// # use arrow_array::{ArrayRef, RunArray};
613/// # use arrow_array::cast::as_run_array;
614/// # use arrow_array::types::Int32Type;
615///
616/// let arr: RunArray<Int32Type> = vec![Some("foo")].into_iter().collect();
617/// let arr: ArrayRef = std::sync::Arc::new(arr);
618/// let run_array: &RunArray<Int32Type> = as_run_array::<Int32Type>(&arr);
619/// ```
620///
621/// # Panics
622///
623/// Panics if `arr` is not a [`RunArray<T>`]
624pub fn as_run_array<T>(arr: &dyn Array) -> &RunArray<T>
625where
626 T: RunEndIndexType,
627{
628 arr.as_any()
629 .downcast_ref::<RunArray<T>>()
630 .expect("Unable to downcast to run array")
631}
632
633#[macro_export]
634#[doc(hidden)]
635macro_rules! downcast_run_array_helper {
636 ($t:ty, $($values:ident),+, $e:block) => {{
637 $(let $values = $crate::cast::as_run_array::<$t>($values);)+
638 $e
639 }};
640}
641
642/// Downcast an [`Array`] to a [`RunArray`] based on its [`DataType`], accepts
643/// a number of subsequent patterns to match the data type
644///
645/// ```
646/// # use arrow_array::{Array, StringArray, downcast_run_array, cast::as_string_array, cast::as_largestring_array};
647/// # use arrow_schema::DataType;
648///
649/// fn print_strings(array: &dyn Array) {
650/// downcast_run_array!(
651/// array => match array.values().data_type() {
652/// DataType::Utf8 => {
653/// for v in array.downcast::<StringArray>().unwrap() {
654/// println!("{:?}", v);
655/// }
656/// }
657/// t => println!("Unsupported run array value type {}", t),
658/// },
659/// DataType::Utf8 => {
660/// for v in as_string_array(array) {
661/// println!("{:?}", v);
662/// }
663/// }
664/// // You can also add a guard to the pattern
665/// DataType::LargeUtf8 if true => {
666/// for v in as_largestring_array(array) {
667/// println!("{:?}", v);
668/// }
669/// }
670/// t => println!("Unsupported datatype {}", t)
671/// )
672/// }
673/// ```
674///
675/// [`DataType`]: arrow_schema::DataType
676#[macro_export]
677macro_rules! downcast_run_array {
678 ($values:ident => $e:expr, $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
679 downcast_run_array!($values => {$e} $($p $(if $pred)? => $fallback,)*)
680 };
681
682 ($values:ident => $e:block $($p:pat $(if $pred:expr)? => $fallback:expr $(,)?)*) => {
683 match $values.data_type() {
684 $crate::cast::__private::DataType::RunEndEncoded(k, _) => {
685 $crate::downcast_run_end_index! {
686 k.data_type() => ($crate::downcast_run_array_helper, $values, $e),
687 k => unreachable!("unsupported run end index type: {}", k)
688 }
689 }
690 $($p $(if $pred)? => $fallback,)*
691 }
692 }
693}
694
695/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
696/// [`GenericListArray<T>`].
697///
698/// # Panics
699///
700/// Panics if `arr` is not a [`GenericListArray<T>`]
701pub fn as_generic_list_array<S: OffsetSizeTrait>(arr: &dyn Array) -> &GenericListArray<S> {
702 arr.as_any()
703 .downcast_ref::<GenericListArray<S>>()
704 .expect("Unable to downcast to list array")
705}
706
707/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
708/// [`ListArray`].
709///
710/// # Panics
711///
712/// Panics if `arr` is not a [`ListArray`]
713#[inline]
714pub fn as_list_array(arr: &dyn Array) -> &ListArray {
715 as_generic_list_array::<i32>(arr)
716}
717
718/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
719/// [`FixedSizeListArray`].
720///
721/// # Panics
722///
723/// Panics if `arr` is not a [`FixedSizeListArray`]
724#[inline]
725pub fn as_fixed_size_list_array(arr: &dyn Array) -> &FixedSizeListArray {
726 arr.as_any()
727 .downcast_ref::<FixedSizeListArray>()
728 .expect("Unable to downcast to fixed size list array")
729}
730
731/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
732/// [`LargeListArray`].
733///
734/// # Panics
735///
736/// Panics if `arr` is not a [`LargeListArray`]
737#[inline]
738pub fn as_large_list_array(arr: &dyn Array) -> &LargeListArray {
739 as_generic_list_array::<i64>(arr)
740}
741
742/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
743/// [`GenericBinaryArray<S>`].
744///
745/// # Panics
746///
747/// Panics if `arr` is not a [`GenericBinaryArray<S>`]
748#[inline]
749pub fn as_generic_binary_array<S: OffsetSizeTrait>(arr: &dyn Array) -> &GenericBinaryArray<S> {
750 arr.as_any()
751 .downcast_ref::<GenericBinaryArray<S>>()
752 .expect("Unable to downcast to binary array")
753}
754
755/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
756/// [`StringArray`].
757///
758/// # Example
759///
760/// ```
761/// # use std::sync::Arc;
762/// # use arrow_array::cast::as_string_array;
763/// # use arrow_array::{ArrayRef, StringArray};
764///
765/// let arr: ArrayRef = Arc::new(StringArray::from_iter(vec![Some("foo")]));
766/// let string_array = as_string_array(&arr);
767/// ```
768///
769/// # Panics
770///
771/// Panics if `arr` is not a [`StringArray`]
772pub fn as_string_array(arr: &dyn Array) -> &StringArray {
773 arr.as_any()
774 .downcast_ref::<StringArray>()
775 .expect("Unable to downcast to StringArray")
776}
777
778/// Force downcast of an [`Array`], such as an [`ArrayRef`] to
779/// [`BooleanArray`].
780///
781/// # Example
782///
783/// ```
784/// # use std::sync::Arc;
785/// # use arrow_array::{ArrayRef, BooleanArray};
786/// # use arrow_array::cast::as_boolean_array;
787///
788/// let arr: ArrayRef = Arc::new(BooleanArray::from_iter(vec![Some(true)]));
789/// let boolean_array = as_boolean_array(&arr);
790/// ```
791///
792/// # Panics
793///
794/// Panics if `arr` is not a [`BooleanArray`]
795pub fn as_boolean_array(arr: &dyn Array) -> &BooleanArray {
796 arr.as_any()
797 .downcast_ref::<BooleanArray>()
798 .expect("Unable to downcast to BooleanArray")
799}
800
801macro_rules! array_downcast_fn {
802 ($name: ident, $arrty: ty, $arrty_str:expr) => {
803 #[doc = "Force downcast of an [`Array`], such as an [`ArrayRef`] to "]
804 #[doc = $arrty_str]
805 #[doc = ""]
806 #[doc = "# Panics"]
807 #[doc = ""]
808 #[doc = "Panics if `arr` is not a "]
809 #[doc = $arrty_str]
810 pub fn $name(arr: &dyn Array) -> &$arrty {
811 arr.as_any().downcast_ref::<$arrty>().expect(concat!(
812 "Unable to downcast to typed array through ",
813 stringify!($name)
814 ))
815 }
816 };
817
818 // use recursive macro to generate dynamic doc string for a given array type
819 ($name: ident, $arrty: ty) => {
820 array_downcast_fn!($name, $arrty, concat!("[`", stringify!($arrty), "`]"));
821 };
822}
823
824array_downcast_fn!(as_largestring_array, LargeStringArray);
825array_downcast_fn!(as_null_array, NullArray);
826array_downcast_fn!(as_struct_array, StructArray);
827array_downcast_fn!(as_union_array, UnionArray);
828array_downcast_fn!(as_map_array, MapArray);
829
830/// Downcasts a `dyn Array` to a concrete type
831///
832/// ```
833/// # use arrow_array::{BooleanArray, Int32Array, RecordBatch, StringArray};
834/// # use arrow_array::cast::downcast_array;
835/// struct ConcreteBatch {
836/// col1: Int32Array,
837/// col2: BooleanArray,
838/// col3: StringArray,
839/// }
840///
841/// impl ConcreteBatch {
842/// fn new(batch: &RecordBatch) -> Self {
843/// Self {
844/// col1: downcast_array(batch.column(0).as_ref()),
845/// col2: downcast_array(batch.column(1).as_ref()),
846/// col3: downcast_array(batch.column(2).as_ref()),
847/// }
848/// }
849/// }
850/// ```
851///
852/// # Panics
853///
854/// Panics if array is not of the correct data type
855pub fn downcast_array<T>(array: &dyn Array) -> T
856where
857 T: From<ArrayData>,
858{
859 T::from(array.to_data())
860}
861
862mod private {
863 pub trait Sealed {}
864}
865
866/// An extension trait for `dyn Array` that provides ergonomic downcasting
867///
868/// ```
869/// # use std::sync::Arc;
870/// # use arrow_array::{ArrayRef, Int32Array};
871/// # use arrow_array::cast::AsArray;
872/// # use arrow_array::types::Int32Type;
873/// let col = Arc::new(Int32Array::from(vec![1, 2, 3])) as ArrayRef;
874/// assert_eq!(col.as_primitive::<Int32Type>().values(), &[1, 2, 3]);
875/// ```
876pub trait AsArray: private::Sealed {
877 /// Downcast this to a [`BooleanArray`] returning `None` if not possible
878 fn as_boolean_opt(&self) -> Option<&BooleanArray>;
879
880 /// Downcast this to a [`BooleanArray`]
881 ///
882 /// # Panics
883 ///
884 /// Panics if this is not a [`BooleanArray`]
885 fn as_boolean(&self) -> &BooleanArray {
886 self.as_boolean_opt().expect("boolean array")
887 }
888
889 /// Downcast this to a [`PrimitiveArray`] returning `None` if not possible
890 fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>>;
891
892 /// Downcast this to a [`PrimitiveArray`]
893 ///
894 /// # Panics
895 ///
896 /// Panics if this is not a [`PrimitiveArray`]
897 fn as_primitive<T: ArrowPrimitiveType>(&self) -> &PrimitiveArray<T> {
898 self.as_primitive_opt().expect("primitive array")
899 }
900
901 /// Downcast this to a [`GenericByteArray`] returning `None` if not possible
902 fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>>;
903
904 /// Downcast this to a [`GenericByteArray`]
905 ///
906 /// # Panics
907 ///
908 /// Panics if this is not a [`GenericByteArray`]
909 fn as_bytes<T: ByteArrayType>(&self) -> &GenericByteArray<T> {
910 self.as_bytes_opt().expect("byte array")
911 }
912
913 /// Downcast this to a [`GenericStringArray`] returning `None` if not possible
914 fn as_string_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericStringArray<O>> {
915 self.as_bytes_opt()
916 }
917
918 /// Downcast this to a [`GenericStringArray`]
919 ///
920 /// # Panics
921 ///
922 /// Panics if this is not a [`GenericStringArray`]
923 fn as_string<O: OffsetSizeTrait>(&self) -> &GenericStringArray<O> {
924 self.as_bytes_opt().expect("string array")
925 }
926
927 /// Downcast this to a [`GenericBinaryArray`] returning `None` if not possible
928 fn as_binary_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericBinaryArray<O>> {
929 self.as_bytes_opt()
930 }
931
932 /// Downcast this to a [`GenericBinaryArray`]
933 ///
934 /// # Panics
935 ///
936 /// Panics if this is not a [`GenericBinaryArray`]
937 fn as_binary<O: OffsetSizeTrait>(&self) -> &GenericBinaryArray<O> {
938 self.as_bytes_opt().expect("binary array")
939 }
940
941 /// Downcast this to a [`StringViewArray`] returning `None` if not possible
942 fn as_string_view_opt(&self) -> Option<&StringViewArray> {
943 self.as_byte_view_opt()
944 }
945
946 /// Downcast this to a [`StringViewArray`]
947 ///
948 /// # Panics
949 ///
950 /// Panics if this is not a [`StringViewArray`]
951 fn as_string_view(&self) -> &StringViewArray {
952 self.as_byte_view_opt().expect("string view array")
953 }
954
955 /// Downcast this to a [`BinaryViewArray`] returning `None` if not possible
956 fn as_binary_view_opt(&self) -> Option<&BinaryViewArray> {
957 self.as_byte_view_opt()
958 }
959
960 /// Downcast this to a [`BinaryViewArray`]
961 ///
962 /// # Panics
963 ///
964 /// Panics if this is not a [`BinaryViewArray`]
965 fn as_binary_view(&self) -> &BinaryViewArray {
966 self.as_byte_view_opt().expect("binary view array")
967 }
968
969 /// Downcast this to a [`GenericByteViewArray`] returning `None` if not possible
970 fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>>;
971
972 /// Downcast this to a [`GenericByteViewArray`]
973 ///
974 /// # Panics
975 ///
976 /// Panics if this is not a [`GenericByteViewArray`]
977 fn as_byte_view<T: ByteViewType>(&self) -> &GenericByteViewArray<T> {
978 self.as_byte_view_opt().expect("byte view array")
979 }
980
981 /// Downcast this to a [`StructArray`] returning `None` if not possible
982 fn as_struct_opt(&self) -> Option<&StructArray>;
983
984 /// Downcast this to a [`StructArray`]
985 ///
986 /// # Panics
987 ///
988 /// Panics if this is not a [`StructArray`]
989 fn as_struct(&self) -> &StructArray {
990 self.as_struct_opt().expect("struct array")
991 }
992
993 /// Downcast this to a [`UnionArray`] returning `None` if not possible
994 fn as_union_opt(&self) -> Option<&UnionArray>;
995
996 /// Downcast this to a [`UnionArray`]
997 ///
998 /// # Panics
999 ///
1000 /// Panics if this is not a [`UnionArray`]
1001 fn as_union(&self) -> &UnionArray {
1002 self.as_union_opt().expect("union array")
1003 }
1004
1005 /// Downcast this to a [`GenericListArray`] returning `None` if not possible
1006 fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>>;
1007
1008 /// Downcast this to a [`GenericListArray`]
1009 ///
1010 /// # Panics
1011 ///
1012 /// Panics if this is not a [`GenericListArray`]
1013 fn as_list<O: OffsetSizeTrait>(&self) -> &GenericListArray<O> {
1014 self.as_list_opt().expect("list array")
1015 }
1016
1017 /// Downcast this to a [`GenericListViewArray`] returning `None` if not possible
1018 fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>>;
1019
1020 /// Downcast this to a [`GenericListViewArray`]
1021 ///
1022 /// # Panics
1023 ///
1024 /// Panics if this is not a [`GenericListViewArray`]
1025 fn as_list_view<O: OffsetSizeTrait>(&self) -> &GenericListViewArray<O> {
1026 self.as_list_view_opt().expect("list view array")
1027 }
1028
1029 /// Downcast this to a [`FixedSizeBinaryArray`] returning `None` if not possible
1030 fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray>;
1031
1032 /// Downcast this to a [`FixedSizeBinaryArray`]
1033 ///
1034 /// # Panics
1035 ///
1036 /// Panics if this is not a [`FixedSizeBinaryArray`]
1037 fn as_fixed_size_binary(&self) -> &FixedSizeBinaryArray {
1038 self.as_fixed_size_binary_opt()
1039 .expect("fixed size binary array")
1040 }
1041
1042 /// Downcast this to a [`FixedSizeListArray`] returning `None` if not possible
1043 fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray>;
1044
1045 /// Downcast this to a [`FixedSizeListArray`]
1046 ///
1047 /// # Panics
1048 ///
1049 /// Panics if this is not a [`FixedSizeListArray`]
1050 fn as_fixed_size_list(&self) -> &FixedSizeListArray {
1051 self.as_fixed_size_list_opt()
1052 .expect("fixed size list array")
1053 }
1054
1055 /// Downcast this to a [`MapArray`] returning `None` if not possible
1056 fn as_map_opt(&self) -> Option<&MapArray>;
1057
1058 /// Downcast this to a [`MapArray`]
1059 ///
1060 /// # Panics
1061 ///
1062 /// Panics if this is not a [`MapArray`]
1063 fn as_map(&self) -> &MapArray {
1064 self.as_map_opt().expect("map array")
1065 }
1066
1067 /// Downcast this to a [`DictionaryArray`] returning `None` if not possible
1068 fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>>;
1069
1070 /// Downcast this to a [`DictionaryArray`]
1071 ///
1072 /// # Panics
1073 ///
1074 /// Panics if this is not a [`DictionaryArray`]
1075 fn as_dictionary<K: ArrowDictionaryKeyType>(&self) -> &DictionaryArray<K> {
1076 self.as_dictionary_opt().expect("dictionary array")
1077 }
1078
1079 /// Downcast this to a [`RunArray`] returning `None` if not possible
1080 fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>>;
1081
1082 /// Downcast this to a [`RunArray`]
1083 ///
1084 /// # Panics
1085 ///
1086 /// Panics if this is not a [`RunArray`]
1087 fn as_run<K: RunEndIndexType>(&self) -> &RunArray<K> {
1088 self.as_run_opt().expect("run array")
1089 }
1090
1091 /// Downcasts this to a [`AnyDictionaryArray`] returning `None` if not possible
1092 fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray>;
1093
1094 /// Downcasts this to a [`AnyDictionaryArray`]
1095 ///
1096 /// # Panics
1097 ///
1098 /// Panics if this is not a [`AnyDictionaryArray`]
1099 fn as_any_dictionary(&self) -> &dyn AnyDictionaryArray {
1100 self.as_any_dictionary_opt().expect("any dictionary array")
1101 }
1102
1103 /// Downcasts this to a [`AnyRunEndArray`] returning `None` if not possible
1104 fn as_any_ree_opt(&self) -> Option<&dyn AnyRunEndArray>;
1105
1106 /// Downcasts this to a [`AnyRunEndArray`]
1107 ///
1108 /// # Panics
1109 ///
1110 /// Panics if this is not a [`AnyRunEndArray`]
1111 fn as_any_ree(&self) -> &dyn AnyRunEndArray {
1112 self.as_any_ree_opt().expect("any run end array")
1113 }
1114}
1115
1116impl private::Sealed for dyn Array + '_ {}
1117impl AsArray for dyn Array + '_ {
1118 fn as_boolean_opt(&self) -> Option<&BooleanArray> {
1119 self.as_any().downcast_ref()
1120 }
1121
1122 fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>> {
1123 self.as_any().downcast_ref()
1124 }
1125
1126 fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>> {
1127 self.as_any().downcast_ref()
1128 }
1129
1130 fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>> {
1131 self.as_any().downcast_ref()
1132 }
1133
1134 fn as_struct_opt(&self) -> Option<&StructArray> {
1135 self.as_any().downcast_ref()
1136 }
1137
1138 fn as_union_opt(&self) -> Option<&UnionArray> {
1139 self.as_any().downcast_ref()
1140 }
1141
1142 fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>> {
1143 self.as_any().downcast_ref()
1144 }
1145
1146 fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>> {
1147 self.as_any().downcast_ref()
1148 }
1149
1150 fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray> {
1151 self.as_any().downcast_ref()
1152 }
1153
1154 fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray> {
1155 self.as_any().downcast_ref()
1156 }
1157
1158 fn as_map_opt(&self) -> Option<&MapArray> {
1159 self.as_any().downcast_ref()
1160 }
1161
1162 fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>> {
1163 self.as_any().downcast_ref()
1164 }
1165
1166 fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>> {
1167 self.as_any().downcast_ref()
1168 }
1169
1170 fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray> {
1171 let array = self;
1172 downcast_dictionary_array! {
1173 array => Some(array),
1174 _ => None
1175 }
1176 }
1177
1178 fn as_any_ree_opt(&self) -> Option<&dyn AnyRunEndArray> {
1179 let array = self;
1180 downcast_run_array! {
1181 array => Some(array),
1182 _ => None
1183 }
1184 }
1185}
1186
1187impl private::Sealed for ArrayRef {}
1188impl AsArray for ArrayRef {
1189 fn as_boolean_opt(&self) -> Option<&BooleanArray> {
1190 self.as_ref().as_boolean_opt()
1191 }
1192
1193 fn as_primitive_opt<T: ArrowPrimitiveType>(&self) -> Option<&PrimitiveArray<T>> {
1194 self.as_ref().as_primitive_opt()
1195 }
1196
1197 fn as_bytes_opt<T: ByteArrayType>(&self) -> Option<&GenericByteArray<T>> {
1198 self.as_ref().as_bytes_opt()
1199 }
1200
1201 fn as_byte_view_opt<T: ByteViewType>(&self) -> Option<&GenericByteViewArray<T>> {
1202 self.as_ref().as_byte_view_opt()
1203 }
1204
1205 fn as_struct_opt(&self) -> Option<&StructArray> {
1206 self.as_ref().as_struct_opt()
1207 }
1208
1209 fn as_union_opt(&self) -> Option<&UnionArray> {
1210 self.as_any().downcast_ref()
1211 }
1212
1213 fn as_list_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListArray<O>> {
1214 self.as_ref().as_list_opt()
1215 }
1216
1217 fn as_list_view_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericListViewArray<O>> {
1218 self.as_ref().as_list_view_opt()
1219 }
1220
1221 fn as_fixed_size_binary_opt(&self) -> Option<&FixedSizeBinaryArray> {
1222 self.as_ref().as_fixed_size_binary_opt()
1223 }
1224
1225 fn as_fixed_size_list_opt(&self) -> Option<&FixedSizeListArray> {
1226 self.as_ref().as_fixed_size_list_opt()
1227 }
1228
1229 fn as_map_opt(&self) -> Option<&MapArray> {
1230 self.as_any().downcast_ref()
1231 }
1232
1233 fn as_dictionary_opt<K: ArrowDictionaryKeyType>(&self) -> Option<&DictionaryArray<K>> {
1234 self.as_ref().as_dictionary_opt()
1235 }
1236
1237 fn as_any_dictionary_opt(&self) -> Option<&dyn AnyDictionaryArray> {
1238 self.as_ref().as_any_dictionary_opt()
1239 }
1240
1241 fn as_any_ree_opt(&self) -> Option<&dyn AnyRunEndArray> {
1242 self.as_ref().as_any_ree_opt()
1243 }
1244
1245 fn as_run_opt<K: RunEndIndexType>(&self) -> Option<&RunArray<K>> {
1246 self.as_ref().as_run_opt()
1247 }
1248
1249 fn as_string_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericStringArray<O>> {
1250 self.as_ref().as_string_opt()
1251 }
1252}
1253
1254#[cfg(test)]
1255mod tests {
1256 use super::*;
1257 use arrow_buffer::i256;
1258 use arrow_schema::DataType;
1259 use std::sync::Arc;
1260
1261 #[test]
1262 fn test_as_primitive_array_ref() {
1263 let array: Int32Array = vec![1, 2, 3].into_iter().map(Some).collect();
1264 assert!(!as_primitive_array::<Int32Type>(&array).is_empty());
1265
1266 // should also work when wrapped in an Arc
1267 let array: ArrayRef = Arc::new(array);
1268 assert!(!as_primitive_array::<Int32Type>(&array).is_empty());
1269 }
1270
1271 #[test]
1272 fn test_as_string_array_ref() {
1273 let array: StringArray = vec!["foo", "bar"].into_iter().map(Some).collect();
1274 assert!(!as_string_array(&array).is_empty());
1275
1276 // should also work when wrapped in an Arc
1277 let array: ArrayRef = Arc::new(array);
1278 assert!(!as_string_array(&array).is_empty())
1279 }
1280
1281 #[test]
1282 fn test_decimal32array() {
1283 let a = Decimal32Array::from_iter_values([1, 2, 4, 5]);
1284 assert!(!as_primitive_array::<Decimal32Type>(&a).is_empty());
1285 }
1286
1287 #[test]
1288 fn test_decimal64array() {
1289 let a = Decimal64Array::from_iter_values([1, 2, 4, 5]);
1290 assert!(!as_primitive_array::<Decimal64Type>(&a).is_empty());
1291 }
1292
1293 #[test]
1294 fn test_decimal128array() {
1295 let a = Decimal128Array::from_iter_values([1, 2, 4, 5]);
1296 assert!(!as_primitive_array::<Decimal128Type>(&a).is_empty());
1297 }
1298
1299 #[test]
1300 fn test_decimal256array() {
1301 let a = Decimal256Array::from_iter_values([1, 2, 4, 5].into_iter().map(i256::from_i128));
1302 assert!(!as_primitive_array::<Decimal256Type>(&a).is_empty());
1303 }
1304
1305 #[test]
1306 fn downcast_integer_array_should_match_only_integers() {
1307 let i32_array: ArrayRef = Arc::new(Int32Array::new_null(1));
1308 let i32_array_ref = &i32_array;
1309 downcast_integer_array!(
1310 i32_array_ref => {
1311 assert_eq!(i32_array_ref.null_count(), 1);
1312 },
1313 _ => panic!("unexpected data type")
1314 );
1315 }
1316
1317 #[test]
1318 fn downcast_integer_array_should_not_match_primitive_that_are_not_integers() {
1319 let array: ArrayRef = Arc::new(Float32Array::new_null(1));
1320 let array_ref = &array;
1321 downcast_integer_array!(
1322 array_ref => {
1323 panic!("unexpected data type {}", array_ref.data_type())
1324 },
1325 DataType::Float32 => {
1326 assert_eq!(array_ref.null_count(), 1);
1327 },
1328 _ => panic!("unexpected data type")
1329 );
1330 }
1331
1332 #[test]
1333 fn downcast_integer_array_should_not_match_non_primitive() {
1334 let array: ArrayRef = Arc::new(StringArray::new_null(1));
1335 let array_ref = &array;
1336 downcast_integer_array!(
1337 array_ref => {
1338 panic!("unexpected data type {}", array_ref.data_type())
1339 },
1340 DataType::Utf8 => {
1341 assert_eq!(array_ref.null_count(), 1);
1342 },
1343 _ => panic!("unexpected data type")
1344 );
1345 }
1346}