#[cfg(feature = "rust_decimal")]
use rust_decimal::MathematicalOps;
#[derive(Clone, Copy, Debug)]
pub enum ArithmeticError {
AddOverflow,
DivOverflow,
MulOverflow,
PowI32Overflow,
PowU32Overflow,
RemOverflow,
SubOverflow,
}
pub trait TryArithmetic<Rhs = Self> {
type Output;
fn try_add(&self, rhs: Rhs) -> crate::Result<Self::Output>;
fn try_div(&self, rhs: Rhs) -> crate::Result<Self::Output>;
fn try_mul(&self, rhs: Rhs) -> crate::Result<Self::Output>;
fn try_pow_i32(&self, exp: i32) -> crate::Result<Self::Output>;
fn try_pow_u32(&self, exp: u32) -> crate::Result<Self::Output>;
fn try_rem(&self, rhs: Rhs) -> crate::Result<Self::Output>;
fn try_sub(&self, rhs: Rhs) -> crate::Result<Self::Output>;
}
#[cfg(feature = "rust_decimal")]
impl TryArithmetic<rust_decimal::Decimal> for rust_decimal::Decimal {
type Output = rust_decimal::Decimal;
#[inline]
fn try_add(&self, rhs: rust_decimal::Decimal) -> crate::Result<Self::Output> {
Ok(self.checked_add(rhs).ok_or(ArithmeticError::AddOverflow)?)
}
#[inline]
fn try_div(&self, rhs: rust_decimal::Decimal) -> crate::Result<Self::Output> {
Ok(self.checked_div(rhs).ok_or(ArithmeticError::DivOverflow)?)
}
#[inline]
fn try_mul(&self, rhs: rust_decimal::Decimal) -> crate::Result<Self::Output> {
Ok(self.checked_mul(rhs).ok_or(ArithmeticError::MulOverflow)?)
}
#[inline]
fn try_pow_i32(&self, rhs: i32) -> crate::Result<Self::Output> {
Ok(self.checked_powi(rhs.into()).ok_or(ArithmeticError::PowI32Overflow)?)
}
#[inline]
fn try_pow_u32(&self, rhs: u32) -> crate::Result<Self::Output> {
Ok(self.checked_powi(rhs.into()).ok_or(ArithmeticError::PowU32Overflow)?)
}
#[inline]
fn try_rem(&self, rhs: rust_decimal::Decimal) -> crate::Result<Self::Output> {
Ok(self.checked_rem(rhs).ok_or(ArithmeticError::RemOverflow)?)
}
#[inline]
fn try_sub(&self, rhs: rust_decimal::Decimal) -> crate::Result<Self::Output> {
Ok(self.checked_sub(rhs).ok_or(ArithmeticError::SubOverflow)?)
}
}
macro_rules! impl_float {
($($ty:ty)*) => {
$(
impl TryArithmetic<$ty> for $ty {
type Output = $ty;
#[inline]
fn try_add(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self + rhs)
}
#[inline]
fn try_div(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self / rhs)
}
#[inline]
fn try_mul(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self * rhs)
}
#[inline]
fn try_pow_i32(&self, _rhs: i32) -> crate::Result<Self::Output> {
#[cfg(feature = "std")]
return Ok(self.powi(_rhs));
#[cfg(not(feature = "std"))]
return Err(crate::Error::UnsupportedOperation);
}
#[inline]
fn try_pow_u32(&self, _rhs: u32) -> crate::Result<Self::Output> {
#[cfg(feature = "std")]
return Ok(self.powi(_rhs.try_into()?));
#[cfg(not(feature = "std"))]
return Err(crate::Error::UnsupportedOperation);
}
#[inline]
fn try_rem(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self % rhs)
}
#[inline]
fn try_sub(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self - rhs)
}
}
)*
};
}
macro_rules! impl_integer {
($($ty:ty)*) => {
$(
impl TryArithmetic<$ty> for $ty {
type Output = $ty;
#[inline]
fn try_add(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self.checked_add(rhs).ok_or(ArithmeticError::AddOverflow)?)
}
#[inline]
fn try_div(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self.checked_div(rhs).ok_or(ArithmeticError::DivOverflow)?)
}
#[inline]
fn try_mul(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self.checked_mul(rhs).ok_or(ArithmeticError::MulOverflow)?)
}
#[inline]
fn try_pow_i32(&self, rhs: i32) -> crate::Result<Self::Output> {
Ok(self.checked_pow(rhs.try_into()?).ok_or(ArithmeticError::PowI32Overflow)?)
}
#[inline]
fn try_pow_u32(&self, rhs: u32) -> crate::Result<Self::Output> {
Ok(self.checked_pow(rhs).ok_or(ArithmeticError::PowU32Overflow)?)
}
#[inline]
fn try_rem(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self.checked_rem(rhs).ok_or(ArithmeticError::RemOverflow)?)
}
#[inline]
fn try_sub(&self, rhs: $ty) -> crate::Result<Self::Output> {
Ok(self.checked_sub(rhs).ok_or(ArithmeticError::SubOverflow)?)
}
}
)*
};
}
impl_float!(f32 f64);
impl_integer!(i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize);