macro_rules! decl_try_from_primitive {
(wide $Type:ident, $Storage:ty, $Src:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<$Src> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: $Src) -> ::core::result::Result<Self, Self::Error> {
<Self as ::core::convert::TryFrom<i128>>::try_from(value as i128)
}
}
};
}
pub(crate) use decl_try_from_primitive;
macro_rules! decl_cross_width_widening {
(wide $Dest:ident, $DestStorage:ty, $Src:ident, $SrcStorage:ty) => {
impl<const SCALE: u32> ::core::convert::From<$Src<SCALE>> for $Dest<SCALE> {
#[inline]
fn from(value: $Src<SCALE>) -> Self {
Self(value.to_bits().resize::<$DestStorage>())
}
}
};
}
pub(crate) use decl_cross_width_widening;
macro_rules! decl_cross_width_narrowing {
(wide $Dest:ident, $DestStorage:ty, $Src:ident, $SrcStorage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<$Src<SCALE>> for $Dest<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: $Src<SCALE>) -> ::core::result::Result<Self, Self::Error> {
let bits = value.to_bits();
let dest_max: $SrcStorage = <$DestStorage>::MAX.resize::<$SrcStorage>();
let dest_min: $SrcStorage = <$DestStorage>::MIN.resize::<$SrcStorage>();
if bits > dest_max || bits < dest_min {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::Overflow,
);
}
::core::result::Result::Ok(Self(bits.resize::<$DestStorage>()))
}
}
};
}
pub(crate) use decl_cross_width_narrowing;
macro_rules! decl_try_from_i128 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<i128> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: i128) -> ::core::result::Result<Self, Self::Error> {
let widened: $Storage = <$Storage>::from_i128(value);
if widened.as_i128() != value {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::Overflow,
);
}
let scaled = widened
.checked_mul(Self::multiplier())
.ok_or($crate::support::error::ConvertError::Overflow)?;
::core::result::Result::Ok(Self(scaled))
}
}
};
}
pub(crate) use decl_try_from_i128;
macro_rules! decl_try_from_u128 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<u128> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: u128) -> ::core::result::Result<Self, Self::Error> {
let widened: $Storage = <$Storage>::from_u128(value);
if widened.is_negative() {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::Overflow,
);
}
if widened.as_u128() != value {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::Overflow,
);
}
let scaled = widened
.checked_mul(Self::multiplier())
.ok_or($crate::support::error::ConvertError::Overflow)?;
::core::result::Result::Ok(Self(scaled))
}
}
};
}
pub(crate) use decl_try_from_u128;
macro_rules! decl_try_from_i64 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<i64> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: i64) -> ::core::result::Result<Self, Self::Error> {
<Self as ::core::convert::TryFrom<i128>>::try_from(value as i128)
}
}
};
}
pub(crate) use decl_try_from_i64;
macro_rules! decl_try_from_u64 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<u64> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: u64) -> ::core::result::Result<Self, Self::Error> {
<Self as ::core::convert::TryFrom<u128>>::try_from(value as u128)
}
}
};
}
pub(crate) use decl_try_from_u64;
macro_rules! decl_try_from_f64 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<f64> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: f64) -> ::core::result::Result<Self, Self::Error> {
if !value.is_finite() {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::NotFinite,
);
}
let mult_f64: f64 = Self::multiplier().as_f64();
let scaled = value * mult_f64;
let storage_max_f64: f64 = <$Storage>::MAX.as_f64();
let storage_min_f64: f64 = <$Storage>::MIN.as_f64();
if !(storage_min_f64..storage_max_f64).contains(&scaled) {
return ::core::result::Result::Err(
$crate::support::error::ConvertError::Overflow,
);
}
let rounded = match $crate::support::rounding::DEFAULT_ROUNDING_MODE {
$crate::support::rounding::RoundingMode::HalfToEven => {
$crate::support::rounding::round_half_even_f64(scaled)
}
$crate::support::rounding::RoundingMode::HalfAwayFromZero => {
$crate::support::rounding::round_half_away_f64(scaled)
}
$crate::support::rounding::RoundingMode::HalfTowardZero => {
$crate::support::rounding::round_half_toward_zero_f64(scaled)
}
$crate::support::rounding::RoundingMode::Trunc => {
$crate::support::rounding::trunc_f64(scaled)
}
$crate::support::rounding::RoundingMode::Floor => {
$crate::support::rounding::floor_f64(scaled)
}
$crate::support::rounding::RoundingMode::Ceiling => {
$crate::support::rounding::ceil_f64(scaled)
}
};
::core::result::Result::Ok(Self(<$Storage>::from_f64(rounded)))
}
}
};
}
macro_rules! decl_try_from_f32 {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::convert::TryFrom<f32> for $Type<SCALE> {
type Error = $crate::support::error::ConvertError;
#[inline]
fn try_from(value: f32) -> ::core::result::Result<Self, Self::Error> {
<Self as ::core::convert::TryFrom<f64>>::try_from(value as f64)
}
}
};
}
pub(crate) use decl_try_from_f32;
pub(crate) use decl_try_from_f64;
macro_rules! decl_decimal_int_conversion_methods {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> $Type<SCALE> {
#[inline]
pub fn to_int(self) -> i64 {
self.to_int_with($crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
#[inline]
pub fn to_int_with(self, mode: $crate::support::rounding::RoundingMode) -> i64 {
let zero = <$Storage>::from_str_radix("0", 10)
.expect("wide decimal: invalid base-10 literal");
let one = <$Storage>::from_str_radix("1", 10)
.expect("wide decimal: invalid base-10 literal");
let raw = self.0;
let divisor = Self::multiplier();
let quotient = raw / divisor;
let remainder = raw % divisor;
let int_rounded: $Storage = if remainder == zero {
quotient
} else {
let abs_rem = remainder.unsigned_abs();
let half = divisor.unsigned_abs() >> 1;
let non_negative = !raw.is_negative();
match mode {
$crate::support::rounding::RoundingMode::HalfToEven => {
if abs_rem < half {
quotient
} else if abs_rem > half {
if non_negative {
quotient + one
} else {
quotient - one
}
} else if !quotient.bit(0) {
quotient
} else if non_negative {
quotient + one
} else {
quotient - one
}
}
$crate::support::rounding::RoundingMode::HalfAwayFromZero => {
if abs_rem < half {
quotient
} else if non_negative {
quotient + one
} else {
quotient - one
}
}
$crate::support::rounding::RoundingMode::HalfTowardZero => {
if abs_rem > half {
if non_negative {
quotient + one
} else {
quotient - one
}
} else {
quotient
}
}
$crate::support::rounding::RoundingMode::Trunc => quotient,
$crate::support::rounding::RoundingMode::Floor => {
if non_negative {
quotient
} else {
quotient - one
}
}
$crate::support::rounding::RoundingMode::Ceiling => {
if non_negative {
quotient + one
} else {
quotient
}
}
}
};
let i64_max: $Storage = <$Storage>::from_i128(i64::MAX as i128);
let i64_min: $Storage = <$Storage>::from_i128(i64::MIN as i128);
if int_rounded > i64_max {
i64::MAX
} else if int_rounded < i64_min {
i64::MIN
} else {
int_rounded.as_i128() as i64
}
}
}
};
}
pub(crate) use decl_decimal_int_conversion_methods;