Skip to content

Commit

Permalink
Added cast for FixedSizeBinary to (Large)Binary (jorgecarleitao#1403)
Browse files Browse the repository at this point in the history
  • Loading branch information
ritchie46 committed Mar 29, 2023
1 parent 2c44e2b commit 5cc49c8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 2 deletions.
28 changes: 27 additions & 1 deletion src/compute/cast/binary_to.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::Result;
use crate::offset::Offset;
use crate::offset::{Offset, Offsets};
use crate::{array::*, datatypes::DataType, types::NativeType};

use super::CastOptions;
Expand Down Expand Up @@ -118,3 +118,29 @@ pub(super) fn binary_to_dictionary_dyn<O: Offset, K: DictionaryKey>(
let values = from.as_any().downcast_ref().unwrap();
binary_to_dictionary::<O, K>(values).map(|x| Box::new(x) as Box<dyn Array>)
}

fn fixed_size_to_offsets<O: Offset>(values_len: usize, fixed_size: usize) -> Offsets<O> {
let offsets = (0..(values_len + 1))
.step_by(fixed_size)
.map(|v| O::from_usize(v).unwrap())
.collect();
// Safety
// * every element is `>= 0`
// * element at position `i` is >= than element at position `i-1`.
unsafe { Offsets::new_unchecked(offsets) }
}

/// Conversion of `FixedSizeBinary` to `Binary`.
pub fn fixed_size_binary_binary<O: Offset>(
from: &FixedSizeBinaryArray,
to_data_type: DataType,
) -> BinaryArray<O> {
let values = from.values().clone();
let offsets = fixed_size_to_offsets(values.len(), from.size());
BinaryArray::<O>::new(
to_data_type,
offsets.into(),
values,
from.validity().cloned(),
)
}
17 changes: 16 additions & 1 deletion src/compute/cast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
is_numeric(to_type) || matches!(to_type, LargeBinary | Utf8 | LargeUtf8)
}
(LargeBinary, to_type) => is_numeric(to_type) || matches!(to_type, Binary | LargeUtf8),

(FixedSizeBinary(_), to_type) => matches!(to_type, Binary | LargeBinary),
(Timestamp(_, _), Utf8) => true,
(Timestamp(_, _), LargeUtf8) => true,
(_, Utf8) => is_numeric(from_type) || from_type == &Binary,
Expand Down Expand Up @@ -686,6 +686,21 @@ pub fn cast(array: &dyn Array, to_type: &DataType, options: CastOptions) -> Resu
"Casting from {from_type:?} to {to_type:?} not supported",
))),
},
(FixedSizeBinary(_), _) => match to_type {
Binary => Ok(fixed_size_binary_binary::<i32>(
array.as_any().downcast_ref().unwrap(),
to_type.clone(),
)
.boxed()),
LargeBinary => Ok(fixed_size_binary_binary::<i64>(
array.as_any().downcast_ref().unwrap(),
to_type.clone(),
)
.boxed()),
_ => Err(Error::NotYetImplemented(format!(
"Casting from {from_type:?} to {to_type:?} not supported",
))),
},

(_, Binary) => match from_type {
UInt8 => primitive_to_binary_dyn::<u8, i32>(array),
Expand Down
32 changes: 32 additions & 0 deletions tests/it/compute/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,38 @@ fn binary_to_i32_partial() {
assert_eq!(c, &expected);
}

#[test]
fn fixed_size_binary_to_binary() {
let slice = [[0, 1], [2, 3]];
let array = FixedSizeBinaryArray::from_slice(slice);

// large-binary
let b = cast(
&array,
&DataType::LargeBinary,
CastOptions {
..Default::default()
},
)
.unwrap();
let c = b.as_any().downcast_ref::<BinaryArray<i64>>().unwrap();
let expected = BinaryArray::<i64>::from_slice(slice);
assert_eq!(c, &expected);

// binary
let b = cast(
&array,
&DataType::Binary,
CastOptions {
..Default::default()
},
)
.unwrap();
let c = b.as_any().downcast_ref::<BinaryArray<i32>>().unwrap();
let expected = BinaryArray::<i32>::from_slice(slice);
assert_eq!(c, &expected);
}

#[test]
fn utf8_to_i32() {
let array = Utf8Array::<i32>::from_slice(["5", "6", "seven", "8", "9.1"]);
Expand Down

0 comments on commit 5cc49c8

Please sign in to comment.