#[forbid(unsafe_code)]
pub mod basic;
#[cfg(feature = "compute_arithmetics_decimal")]
pub mod decimal;
pub mod time;
use crate::{
array::{Array, DictionaryArray, PrimitiveArray},
bitmap::Bitmap,
datatypes::{DataType, IntervalUnit, TimeUnit},
scalar::{PrimitiveScalar, Scalar},
types::NativeType,
};
fn binary_dyn<T: NativeType, F: Fn(&PrimitiveArray<T>, &PrimitiveArray<T>) -> PrimitiveArray<T>>(
lhs: &dyn Array,
rhs: &dyn Array,
op: F,
) -> Box<dyn Array> {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
op(lhs, rhs).boxed()
}
macro_rules! arith {
($lhs:expr, $rhs:expr, $op:tt $(, decimal = $op_decimal:tt )? $(, duration = $op_duration:tt )? $(, interval = $op_interval:tt )? $(, timestamp = $op_timestamp:tt )?) => {{
let lhs = $lhs;
let rhs = $rhs;
use DataType::*;
match (lhs.data_type(), rhs.data_type()) {
(Int8, Int8) => binary_dyn::<i8, _>(lhs, rhs, basic::$op),
(Int16, Int16) => binary_dyn::<i16, _>(lhs, rhs, basic::$op),
(Int32, Int32) => binary_dyn::<i32, _>(lhs, rhs, basic::$op),
(Int64, Int64) | (Duration(_), Duration(_)) => {
binary_dyn::<i64, _>(lhs, rhs, basic::$op)
}
(UInt8, UInt8) => binary_dyn::<u8, _>(lhs, rhs, basic::$op),
(UInt16, UInt16) => binary_dyn::<u16, _>(lhs, rhs, basic::$op),
(UInt32, UInt32) => binary_dyn::<u32, _>(lhs, rhs, basic::$op),
(UInt64, UInt64) => binary_dyn::<u64, _>(lhs, rhs, basic::$op),
(Float32, Float32) => binary_dyn::<f32, _>(lhs, rhs, basic::$op),
(Float64, Float64) => binary_dyn::<f64, _>(lhs, rhs, basic::$op),
$ (
(Decimal(_, _), Decimal(_, _)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
Box::new(decimal::$op_decimal(lhs, rhs)) as Box<dyn Array>
}
)?
$ (
(Time32(TimeUnit::Second), Duration(_))
| (Time32(TimeUnit::Millisecond), Duration(_))
| (Date32, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
Box::new(time::$op_duration::<i32>(lhs, rhs)) as Box<dyn Array>
}
(Time64(TimeUnit::Microsecond), Duration(_))
| (Time64(TimeUnit::Nanosecond), Duration(_))
| (Date64, Duration(_))
| (Timestamp(_, _), Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
Box::new(time::$op_duration::<i64>(lhs, rhs)) as Box<dyn Array>
}
)?
$ (
(Timestamp(_, _), Interval(IntervalUnit::MonthDayNano)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_interval(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>).unwrap()
}
)?
$ (
(Timestamp(_, None), Timestamp(_, None)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_timestamp(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>).unwrap()
}
)?
_ => todo!(
"Addition of {:?} with {:?} is not supported",
lhs.data_type(),
rhs.data_type()
),
}
}};
}
fn binary_scalar<T: NativeType, F: Fn(&PrimitiveArray<T>, &T) -> PrimitiveArray<T>>(
lhs: &PrimitiveArray<T>,
rhs: &PrimitiveScalar<T>,
op: F,
) -> PrimitiveArray<T> {
let rhs = if let Some(rhs) = *rhs.value() {
rhs
} else {
return PrimitiveArray::<T>::new_null(lhs.data_type().clone(), lhs.len());
};
op(lhs, &rhs)
}
fn binary_scalar_dyn<T: NativeType, F: Fn(&PrimitiveArray<T>, &T) -> PrimitiveArray<T>>(
lhs: &dyn Array,
rhs: &dyn Scalar,
op: F,
) -> Box<dyn Array> {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
binary_scalar(lhs, rhs, op).boxed()
}
macro_rules! arith_scalar {
($lhs:expr, $rhs:expr, $op:tt $(, decimal = $op_decimal:tt )? $(, duration = $op_duration:tt )? $(, interval = $op_interval:tt )? $(, timestamp = $op_timestamp:tt )?) => {{
let lhs = $lhs;
let rhs = $rhs;
use DataType::*;
match (lhs.data_type(), rhs.data_type()) {
(Int8, Int8) => binary_scalar_dyn::<i8, _>(lhs, rhs, basic::$op),
(Int16, Int16) => binary_scalar_dyn::<i16, _>(lhs, rhs, basic::$op),
(Int32, Int32) => binary_scalar_dyn::<i32, _>(lhs, rhs, basic::$op),
(Int64, Int64) | (Duration(_), Duration(_)) => {
binary_scalar_dyn::<i64, _>(lhs, rhs, basic::$op)
}
(UInt8, UInt8) => binary_scalar_dyn::<u8, _>(lhs, rhs, basic::$op),
(UInt16, UInt16) => binary_scalar_dyn::<u16, _>(lhs, rhs, basic::$op),
(UInt32, UInt32) => binary_scalar_dyn::<u32, _>(lhs, rhs, basic::$op),
(UInt64, UInt64) => binary_scalar_dyn::<u64, _>(lhs, rhs, basic::$op),
(Float32, Float32) => binary_scalar_dyn::<f32, _>(lhs, rhs, basic::$op),
(Float64, Float64) => binary_scalar_dyn::<f64, _>(lhs, rhs, basic::$op),
$ (
(Decimal(_, _), Decimal(_, _)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
decimal::$op_decimal(lhs, rhs).boxed()
}
)?
$ (
(Time32(TimeUnit::Second), Duration(_))
| (Time32(TimeUnit::Millisecond), Duration(_))
| (Date32, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_duration::<i32>(lhs, rhs).boxed()
}
(Time64(TimeUnit::Microsecond), Duration(_))
| (Time64(TimeUnit::Nanosecond), Duration(_))
| (Date64, Duration(_))
| (Timestamp(_, _), Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_duration::<i64>(lhs, rhs).boxed()
}
)?
$ (
(Timestamp(_, _), Interval(IntervalUnit::MonthDayNano)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_interval(lhs, rhs).unwrap().boxed()
}
)?
$ (
(Timestamp(_, None), Timestamp(_, None)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::$op_timestamp(lhs, rhs).unwrap().boxed()
}
)?
_ => todo!(
"Addition of {:?} with {:?} is not supported",
lhs.data_type(),
rhs.data_type()
),
}
}};
}
pub fn add(lhs: &dyn Array, rhs: &dyn Array) -> Box<dyn Array> {
arith!(
lhs,
rhs,
add,
duration = add_duration,
interval = add_interval
)
}
pub fn add_scalar(lhs: &dyn Array, rhs: &dyn Scalar) -> Box<dyn Array> {
arith_scalar!(
lhs,
rhs,
add_scalar,
duration = add_duration_scalar,
interval = add_interval_scalar
)
}
pub fn can_add(lhs: &DataType, rhs: &DataType) -> bool {
use DataType::*;
matches!(
(lhs, rhs),
(Int8, Int8)
| (Int16, Int16)
| (Int32, Int32)
| (Int64, Int64)
| (UInt8, UInt8)
| (UInt16, UInt16)
| (UInt32, UInt32)
| (UInt64, UInt64)
| (Float64, Float64)
| (Float32, Float32)
| (Duration(_), Duration(_))
| (Decimal(_, _), Decimal(_, _))
| (Date32, Duration(_))
| (Date64, Duration(_))
| (Time32(TimeUnit::Millisecond), Duration(_))
| (Time32(TimeUnit::Second), Duration(_))
| (Time64(TimeUnit::Microsecond), Duration(_))
| (Time64(TimeUnit::Nanosecond), Duration(_))
| (Timestamp(_, _), Duration(_))
| (Timestamp(_, _), Interval(IntervalUnit::MonthDayNano))
)
}
pub fn sub(lhs: &dyn Array, rhs: &dyn Array) -> Box<dyn Array> {
arith!(
lhs,
rhs,
sub,
decimal = sub,
duration = subtract_duration,
timestamp = subtract_timestamps
)
}
pub fn sub_scalar(lhs: &dyn Array, rhs: &dyn Scalar) -> Box<dyn Array> {
arith_scalar!(
lhs,
rhs,
sub_scalar,
duration = sub_duration_scalar,
timestamp = sub_timestamps_scalar
)
}
pub fn can_sub(lhs: &DataType, rhs: &DataType) -> bool {
use DataType::*;
matches!(
(lhs, rhs),
(Int8, Int8)
| (Int16, Int16)
| (Int32, Int32)
| (Int64, Int64)
| (UInt8, UInt8)
| (UInt16, UInt16)
| (UInt32, UInt32)
| (UInt64, UInt64)
| (Float64, Float64)
| (Float32, Float32)
| (Duration(_), Duration(_))
| (Decimal(_, _), Decimal(_, _))
| (Date32, Duration(_))
| (Date64, Duration(_))
| (Time32(TimeUnit::Millisecond), Duration(_))
| (Time32(TimeUnit::Second), Duration(_))
| (Time64(TimeUnit::Microsecond), Duration(_))
| (Time64(TimeUnit::Nanosecond), Duration(_))
| (Timestamp(_, _), Duration(_))
| (Timestamp(_, None), Timestamp(_, None))
)
}
pub fn mul(lhs: &dyn Array, rhs: &dyn Array) -> Box<dyn Array> {
arith!(lhs, rhs, mul, decimal = mul)
}
pub fn mul_scalar(lhs: &dyn Array, rhs: &dyn Scalar) -> Box<dyn Array> {
arith_scalar!(lhs, rhs, mul_scalar, decimal = mul_scalar)
}
pub fn can_mul(lhs: &DataType, rhs: &DataType) -> bool {
use DataType::*;
matches!(
(lhs, rhs),
(Int8, Int8)
| (Int16, Int16)
| (Int32, Int32)
| (Int64, Int64)
| (UInt8, UInt8)
| (UInt16, UInt16)
| (UInt32, UInt32)
| (UInt64, UInt64)
| (Float64, Float64)
| (Float32, Float32)
| (Decimal(_, _), Decimal(_, _))
)
}
pub fn div(lhs: &dyn Array, rhs: &dyn Array) -> Box<dyn Array> {
arith!(lhs, rhs, div, decimal = div)
}
pub fn div_scalar(lhs: &dyn Array, rhs: &dyn Scalar) -> Box<dyn Array> {
arith_scalar!(lhs, rhs, div_scalar, decimal = div_scalar)
}
pub fn can_div(lhs: &DataType, rhs: &DataType) -> bool {
can_mul(lhs, rhs)
}
pub fn rem(lhs: &dyn Array, rhs: &dyn Array) -> Box<dyn Array> {
arith!(lhs, rhs, rem)
}
pub fn can_rem(lhs: &DataType, rhs: &DataType) -> bool {
use DataType::*;
matches!(
(lhs, rhs),
(Int8, Int8)
| (Int16, Int16)
| (Int32, Int32)
| (Int64, Int64)
| (UInt8, UInt8)
| (UInt16, UInt16)
| (UInt32, UInt32)
| (UInt64, UInt64)
| (Float64, Float64)
| (Float32, Float32)
)
}
macro_rules! with_match_negatable {(
$key_type:expr, | $_:tt $T:ident | $($body:tt)*
) => ({
macro_rules! __with_ty__ {( $_ $T:ident ) => ( $($body)* )}
use crate::datatypes::PrimitiveType::*;
use crate::types::{days_ms, months_days_ns, i256};
match $key_type {
Int8 => __with_ty__! { i8 },
Int16 => __with_ty__! { i16 },
Int32 => __with_ty__! { i32 },
Int64 => __with_ty__! { i64 },
Int128 => __with_ty__! { i128 },
Int256 => __with_ty__! { i256 },
DaysMs => __with_ty__! { days_ms },
MonthDayNano => __with_ty__! { months_days_ns },
UInt8 | UInt16 | UInt32 | UInt64 | Float16 => todo!(),
Float32 => __with_ty__! { f32 },
Float64 => __with_ty__! { f64 },
}
})}
pub fn neg(array: &dyn Array) -> Box<dyn Array> {
use crate::datatypes::PhysicalType::*;
match array.data_type().to_physical_type() {
Primitive(primitive) => with_match_negatable!(primitive, |$T| {
let array = array.as_any().downcast_ref().unwrap();
let result = basic::negate::<$T>(array);
Box::new(result) as Box<dyn Array>
}),
Dictionary(key) => match_integer_type!(key, |$T| {
let array = array.as_any().downcast_ref::<DictionaryArray<$T>>().unwrap();
let values = neg(array.values().as_ref());
unsafe{
DictionaryArray::<$T>::try_new_unchecked(array.data_type().clone(), array.keys().clone(), values).unwrap().boxed()
}
}),
_ => todo!(),
}
}
pub fn can_neg(data_type: &DataType) -> bool {
if let DataType::Dictionary(_, values, _) = data_type.to_logical_type() {
return can_neg(values.as_ref());
}
use crate::datatypes::PhysicalType::*;
use crate::datatypes::PrimitiveType::*;
matches!(
data_type.to_physical_type(),
Primitive(Int8)
| Primitive(Int16)
| Primitive(Int32)
| Primitive(Int64)
| Primitive(Float64)
| Primitive(Float32)
| Primitive(DaysMs)
| Primitive(MonthDayNano)
)
}
pub trait ArrayAdd<Rhs>: Sized {
fn add(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayWrappingAdd<Rhs>: Sized {
fn wrapping_add(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayCheckedAdd<Rhs>: Sized {
fn checked_add(&self, rhs: &Rhs) -> Self;
}
pub trait ArraySaturatingAdd<Rhs>: Sized {
fn saturating_add(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayOverflowingAdd<Rhs>: Sized {
fn overflowing_add(&self, rhs: &Rhs) -> (Self, Bitmap);
}
pub trait ArraySub<Rhs>: Sized {
fn sub(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayWrappingSub<Rhs>: Sized {
fn wrapping_sub(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayCheckedSub<Rhs>: Sized {
fn checked_sub(&self, rhs: &Rhs) -> Self;
}
pub trait ArraySaturatingSub<Rhs>: Sized {
fn saturating_sub(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayOverflowingSub<Rhs>: Sized {
fn overflowing_sub(&self, rhs: &Rhs) -> (Self, Bitmap);
}
pub trait ArrayMul<Rhs>: Sized {
fn mul(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayWrappingMul<Rhs>: Sized {
fn wrapping_mul(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayCheckedMul<Rhs>: Sized {
fn checked_mul(&self, rhs: &Rhs) -> Self;
}
pub trait ArraySaturatingMul<Rhs>: Sized {
fn saturating_mul(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayOverflowingMul<Rhs>: Sized {
fn overflowing_mul(&self, rhs: &Rhs) -> (Self, Bitmap);
}
pub trait ArrayDiv<Rhs>: Sized {
fn div(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayCheckedDiv<Rhs>: Sized {
fn checked_div(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayRem<Rhs>: Sized {
fn rem(&self, rhs: &Rhs) -> Self;
}
pub trait ArrayCheckedRem<Rhs>: Sized {
fn checked_rem(&self, rhs: &Rhs) -> Self;
}