use arrow_buffer::{i256, ArrowNativeType};
use arrow_schema::ArrowError;
use half::f16;
use num::complex::ComplexFloat;
use std::cmp::Ordering;
pub trait ArrowNativeTypeOp: ArrowNativeType {
const ZERO: Self;
const ONE: Self;
fn add_checked(self, rhs: Self) -> Result<Self, ArrowError>;
fn add_wrapping(self, rhs: Self) -> Self;
fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError>;
fn sub_wrapping(self, rhs: Self) -> Self;
fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError>;
fn mul_wrapping(self, rhs: Self) -> Self;
fn div_checked(self, rhs: Self) -> Result<Self, ArrowError>;
fn div_wrapping(self, rhs: Self) -> Self;
fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError>;
fn mod_wrapping(self, rhs: Self) -> Self;
fn neg_checked(self) -> Result<Self, ArrowError>;
fn neg_wrapping(self) -> Self;
fn pow_checked(self, exp: u32) -> Result<Self, ArrowError>;
fn pow_wrapping(self, exp: u32) -> Self;
fn is_zero(self) -> bool;
fn compare(self, rhs: Self) -> Ordering;
fn is_eq(self, rhs: Self) -> bool;
#[inline]
fn is_ne(self, rhs: Self) -> bool {
!self.is_eq(rhs)
}
#[inline]
fn is_lt(self, rhs: Self) -> bool {
self.compare(rhs).is_lt()
}
#[inline]
fn is_le(self, rhs: Self) -> bool {
self.compare(rhs).is_le()
}
#[inline]
fn is_gt(self, rhs: Self) -> bool {
self.compare(rhs).is_gt()
}
#[inline]
fn is_ge(self, rhs: Self) -> bool {
self.compare(rhs).is_ge()
}
}
macro_rules! native_type_op {
($t:tt) => {
native_type_op!($t, 0, 1);
};
($t:tt, $zero:expr, $one: expr) => {
impl ArrowNativeTypeOp for $t {
const ZERO: Self = $zero;
const ONE: Self = $one;
#[inline]
fn add_checked(self, rhs: Self) -> Result<Self, ArrowError> {
self.checked_add(rhs).ok_or_else(|| {
ArrowError::ComputeError(format!(
"Overflow happened on: {:?} + {:?}",
self, rhs
))
})
}
#[inline]
fn add_wrapping(self, rhs: Self) -> Self {
self.wrapping_add(rhs)
}
#[inline]
fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
self.checked_sub(rhs).ok_or_else(|| {
ArrowError::ComputeError(format!(
"Overflow happened on: {:?} - {:?}",
self, rhs
))
})
}
#[inline]
fn sub_wrapping(self, rhs: Self) -> Self {
self.wrapping_sub(rhs)
}
#[inline]
fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
self.checked_mul(rhs).ok_or_else(|| {
ArrowError::ComputeError(format!(
"Overflow happened on: {:?} * {:?}",
self, rhs
))
})
}
#[inline]
fn mul_wrapping(self, rhs: Self) -> Self {
self.wrapping_mul(rhs)
}
#[inline]
fn div_checked(self, rhs: Self) -> Result<Self, ArrowError> {
if rhs.is_zero() {
Err(ArrowError::DivideByZero)
} else {
self.checked_div(rhs).ok_or_else(|| {
ArrowError::ComputeError(format!(
"Overflow happened on: {:?} / {:?}",
self, rhs
))
})
}
}
#[inline]
fn div_wrapping(self, rhs: Self) -> Self {
self.wrapping_div(rhs)
}
#[inline]
fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError> {
if rhs.is_zero() {
Err(ArrowError::DivideByZero)
} else {
self.checked_rem(rhs).ok_or_else(|| {
ArrowError::ComputeError(format!(
"Overflow happened on: {:?} % {:?}",
self, rhs
))
})
}
}
#[inline]
fn mod_wrapping(self, rhs: Self) -> Self {
self.wrapping_rem(rhs)
}
#[inline]
fn neg_checked(self) -> Result<Self, ArrowError> {
self.checked_neg().ok_or_else(|| {
ArrowError::ComputeError(format!("Overflow happened on: {:?}", self))
})
}
#[inline]
fn pow_checked(self, exp: u32) -> Result<Self, ArrowError> {
self.checked_pow(exp).ok_or_else(|| {
ArrowError::ComputeError(format!("Overflow happened on: {:?}", self))
})
}
#[inline]
fn pow_wrapping(self, exp: u32) -> Self {
self.wrapping_pow(exp)
}
#[inline]
fn neg_wrapping(self) -> Self {
self.wrapping_neg()
}
#[inline]
fn is_zero(self) -> bool {
self == Self::ZERO
}
#[inline]
fn compare(self, rhs: Self) -> Ordering {
self.cmp(&rhs)
}
#[inline]
fn is_eq(self, rhs: Self) -> bool {
self == rhs
}
}
};
}
native_type_op!(i8);
native_type_op!(i16);
native_type_op!(i32);
native_type_op!(i64);
native_type_op!(i128);
native_type_op!(u8);
native_type_op!(u16);
native_type_op!(u32);
native_type_op!(u64);
native_type_op!(i256, i256::ZERO, i256::ONE);
macro_rules! native_type_float_op {
($t:tt, $zero:expr, $one:expr) => {
impl ArrowNativeTypeOp for $t {
const ZERO: Self = $zero;
const ONE: Self = $one;
#[inline]
fn add_checked(self, rhs: Self) -> Result<Self, ArrowError> {
Ok(self + rhs)
}
#[inline]
fn add_wrapping(self, rhs: Self) -> Self {
self + rhs
}
#[inline]
fn sub_checked(self, rhs: Self) -> Result<Self, ArrowError> {
Ok(self - rhs)
}
#[inline]
fn sub_wrapping(self, rhs: Self) -> Self {
self - rhs
}
#[inline]
fn mul_checked(self, rhs: Self) -> Result<Self, ArrowError> {
Ok(self * rhs)
}
#[inline]
fn mul_wrapping(self, rhs: Self) -> Self {
self * rhs
}
#[inline]
fn div_checked(self, rhs: Self) -> Result<Self, ArrowError> {
if rhs.is_zero() {
Err(ArrowError::DivideByZero)
} else {
Ok(self / rhs)
}
}
#[inline]
fn div_wrapping(self, rhs: Self) -> Self {
self / rhs
}
#[inline]
fn mod_checked(self, rhs: Self) -> Result<Self, ArrowError> {
if rhs.is_zero() {
Err(ArrowError::DivideByZero)
} else {
Ok(self % rhs)
}
}
#[inline]
fn mod_wrapping(self, rhs: Self) -> Self {
self % rhs
}
#[inline]
fn neg_checked(self) -> Result<Self, ArrowError> {
Ok(-self)
}
#[inline]
fn neg_wrapping(self) -> Self {
-self
}
#[inline]
fn pow_checked(self, exp: u32) -> Result<Self, ArrowError> {
Ok(self.powi(exp as i32))
}
#[inline]
fn pow_wrapping(self, exp: u32) -> Self {
self.powi(exp as i32)
}
#[inline]
fn is_zero(self) -> bool {
self == $zero
}
#[inline]
fn compare(self, rhs: Self) -> Ordering {
<$t>::total_cmp(&self, &rhs)
}
#[inline]
fn is_eq(self, rhs: Self) -> bool {
self.to_bits() == rhs.to_bits()
}
}
};
}
native_type_float_op!(f16, f16::ONE, f16::ZERO);
native_type_float_op!(f32, 0., 1.);
native_type_float_op!(f64, 0., 1.);