Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Add array::downcast_ref and array::downcast_mut #1566

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ odbc-api = { version = "0.36", optional = true }
# Faster hashing
ahash = "0.8"

# workaround for pre-polonius borrow checker
polonius-the-crab = "0.3"
aldanor marked this conversation as resolved.
Show resolved Hide resolved

# Support conversion to/from arrow-rs
arrow-buffer = { version = ">=40", optional = true }
arrow-schema = { version = ">=40", optional = true }
Expand Down
96 changes: 94 additions & 2 deletions src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
//!
//! Most arrays contain a [`MutableArray`] counterpart that is neither clonable nor slicable, but
//! can be operated in-place.
use std::any::Any;
use std::any::{type_name, Any};
use std::sync::Arc;

use crate::error::Result;
use crate::error::{Error, Result};
use crate::{
bitmap::{Bitmap, MutableBitmap},
datatypes::DataType,
Expand Down Expand Up @@ -142,6 +142,12 @@ pub trait Array: Send + Sync + dyn_clone::DynClone + 'static {

/// Clone a `&dyn Array` to an owned `Box<dyn Array>`.
fn to_boxed(&self) -> Box<dyn Array>;

#[doc(hidden)]
#[inline]
fn as_mut_any(&mut self) -> &mut dyn Any {
self.as_any_mut()
}
}

dyn_clone::clone_trait_object!(Array);
Expand Down Expand Up @@ -703,6 +709,92 @@ impl<'a> AsRef<(dyn Array + 'a)> for dyn Array {
}
}

mod downcast {
use super::{Array, DataType, MutableArray};
use std::any::Any;

/// Arrays that can be downcasted to a concrete type ([`Array`] and [`MutableArray`]).
pub trait ArrayAny {
/// The [`DataType`] of the array.
fn data_type(&self) -> &DataType;
/// Converts itself to a reference of [`Any`].
fn as_any(&self) -> &dyn Any;
/// Converts itself to a mutable reference of [`Any`].
fn as_mut_any(&mut self) -> &mut dyn Any;
}

macro_rules! impl_array_any {
($ty:ident) => {
impl ArrayAny for dyn $ty {
#[inline]
fn data_type(&self) -> &DataType {
$ty::data_type(self)
}

#[inline]
fn as_any(&self) -> &dyn Any {
$ty::as_any(self)
}

#[inline]
fn as_mut_any(&mut self) -> &mut dyn Any {
$ty::as_mut_any(self)
}
}

impl ArrayAny for Box<dyn $ty> {
#[inline]
fn data_type(&self) -> &DataType {
$ty::data_type(self.as_ref())
}

#[inline]
fn as_any(&self) -> &dyn Any {
$ty::as_any(self.as_ref())
}

#[inline]
fn as_mut_any(&mut self) -> &mut dyn Any {
$ty::as_mut_any(self.as_mut())
}
}
};
}

impl_array_any!(Array);
impl_array_any!(MutableArray);
}

/// Downcast an array reference to a concrete type.
#[inline]
pub fn downcast_ref<M: 'static>(array: &(impl downcast::ArrayAny + ?Sized)) -> Result<&M> {
array.as_any().downcast_ref().ok_or_else(|| {
Error::oos(format!(
"Unable to downcast array of data type {:?} into {}",
array.data_type(),
type_name::<M>()
))
})
}

/// Downcast a mutable array reference to a concrete type.
#[inline]
pub fn downcast_mut<M: 'static>(
mut array: &mut (impl downcast::ArrayAny + ?Sized),
) -> Result<&mut M> {
use polonius_the_crab::{polonius, polonius_return};
polonius!(|array| -> Result<&'polonius mut M> {
if let Some(array) = array.as_mut_any().downcast_mut::<M>() {
polonius_return!(Ok(array));
}
});
Err(Error::oos(format!(
"Unable to downcast array of data type {:?} into {}",
array.data_type(),
type_name::<M>()
)))
}

mod binary;
mod boolean;
mod dictionary;
Expand Down
29 changes: 28 additions & 1 deletion tests/it/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ mod struct_;
mod union;
mod utf8;

use arrow2::array::{clone, new_empty_array, new_null_array, Array, PrimitiveArray};
use arrow2::array::{
clone, downcast_mut, downcast_ref, new_empty_array, new_null_array, Array, MutableArray,
MutablePrimitiveArray, PrimitiveArray,
};
use arrow2::bitmap::Bitmap;
use arrow2::datatypes::{DataType, Field, UnionMode};

Expand Down Expand Up @@ -140,3 +143,27 @@ fn test_with_validity() {
struct A {
array: Box<dyn Array>,
}

#[test]
fn test_downcast() {
let arr = PrimitiveArray::from_slice([1i32, 2, 3]);
let arr_box: Box<dyn Array> = Box::new(arr.clone());
assert_eq!(downcast_ref::<PrimitiveArray<i32>>(&arr_box).unwrap(), &arr);
assert_eq!(
downcast_ref::<PrimitiveArray<i32>>(arr_box.as_ref()).unwrap(),
&arr
);
assert!(downcast_ref::<PrimitiveArray<u8>>(&arr_box).is_err());

let mut_arr = MutablePrimitiveArray::from_slice([1i32, 2, 3]);
let mut mut_arr_box: Box<dyn MutableArray> = Box::new(mut_arr.clone());
assert_eq!(
downcast_mut::<MutablePrimitiveArray<i32>>(&mut mut_arr_box).unwrap(),
&mut_arr
);
assert_eq!(
downcast_mut::<MutablePrimitiveArray<i32>>(mut_arr_box.as_mut()).unwrap(),
&mut_arr
);
assert!(downcast_mut::<MutablePrimitiveArray<u8>>(&mut mut_arr_box).is_err());
}