Skip to content

Commit

Permalink
feat: impl num_traits::Num and num_traits::Signed for Decimal (#11
Browse files Browse the repository at this point in the history
)
  • Loading branch information
MathisWellmann authored and OliverNChalk committed Oct 18, 2024
1 parent 18c9eac commit 4015783
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
61 changes: 56 additions & 5 deletions src/decimal.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use std::str::FromStr;

use crate::display::ParseDecimalError;
use crate::integer::{ScaledInteger, SignedScaledInteger};

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -97,7 +99,47 @@ where
{
#[inline]
fn one() -> Self {
Self(I::one() * <I as crate::cheats::Cheats<D>>::SCALING_FACTOR)
Self(I::SCALING_FACTOR)
}
}

impl<I, const D: u8> num_traits::Num for Decimal<I, D>
where
I: SignedScaledInteger<D>,
{
type FromStrRadixErr = ParseDecimalError<I>;

fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
if radix != 10 {
return Err(ParseDecimalError::RadixMustBe10);
}

Self::from_str(str)
}
}

impl<I, const D: u8> num_traits::Signed for Decimal<I, D>
where
I: SignedScaledInteger<D>,
{
fn abs(&self) -> Self {
Self(self.0.abs())
}

fn abs_sub(&self, other: &Self) -> Self {
Self(self.0.abs_sub(&other.0))
}

fn signum(&self) -> Self {
Self(self.0.signum())
}

fn is_positive(&self) -> bool {
self.0.is_positive()
}

fn is_negative(&self) -> bool {
self.0.is_negative()
}
}

Expand Down Expand Up @@ -157,7 +199,7 @@ where

#[inline]
fn rem(self, rhs: Self) -> Self::Output {
Self(self.0 % rhs.0)
Self(self.0.checked_rem(&rhs.0).unwrap())
}
}

Expand Down Expand Up @@ -231,9 +273,18 @@ mod tests {
#[test]
fn [<num_traits_one_ $underlying _ $decimals _add>]() {
use num_traits::One;
assert_eq!(Decimal::<$underlying, $decimals>::one(), Decimal::try_from_scaled(1, 0).unwrap());
assert_eq!(Decimal::<$underlying, $decimals>::one(), Decimal::try_from_scaled(10, 1).unwrap());
assert_eq!(Decimal::<$underlying, $decimals>::one(), Decimal::try_from_scaled(100, 2).unwrap());
assert_eq!(
Decimal::<$underlying, $decimals>::one(),
Decimal::try_from_scaled(1, 0).unwrap(),
);
assert_eq!(
Decimal::<$underlying, $decimals>::one(),
Decimal::try_from_scaled(10, 1).unwrap(),
);
assert_eq!(
Decimal::<$underlying, $decimals>::one(),
Decimal::try_from_scaled(100, 2).unwrap(),
);
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ where
ParseInt(#[from] ParseIntError),
#[error("Could not parse without precision loss; decimals={0}")]
PrecisionLoss(usize),
#[error("The radix must be 10 in `from_str_radix`")]
RadixMustBe10,
}

#[cfg(test)]
Expand Down
10 changes: 8 additions & 2 deletions src/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ impl<I, const D: u8> ScaledInteger<D> for I where
{
}

pub trait SignedScaledInteger<const D: u8>: ScaledInteger<D> + CheckedNeg {}
pub trait SignedScaledInteger<const D: u8>:
ScaledInteger<D> + CheckedNeg + num_traits::Signed
{
}

impl<I, const D: u8> SignedScaledInteger<D> for I where I: ScaledInteger<D> + CheckedNeg {}
impl<I, const D: u8> SignedScaledInteger<D> for I where
I: ScaledInteger<D> + CheckedNeg + num_traits::Signed
{
}

0 comments on commit 4015783

Please sign in to comment.