Skip to content

Commit

Permalink
feat: basic ops for u64/i64/u128/i128
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverNChalk committed Sep 11, 2024
1 parent 39cc201 commit b0429e8
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 72 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ disallowed_methods = 'warn'
serde = ["dep:serde"]

[dependencies]
num-traits = "0.2.19"
serde = { version = "1.0.210", features = ["derive"], optional = true }

[build-dependencies]
[dev-dependencies]
paste = "1.0.15"

[profile.release]
opt-level = 3
Expand Down
19 changes: 19 additions & 0 deletions src/const_traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub trait PrecisionFactor<const D: u8> {
const PRECISION_FACTOR: Self;
}

impl<const D: u8> PrecisionFactor<D> for u64 {
const PRECISION_FACTOR: Self = 10u64.pow(D as u32);
}

impl<const D: u8> PrecisionFactor<D> for i64 {
const PRECISION_FACTOR: Self = 10i64.pow(D as u32);
}

impl<const D: u8> PrecisionFactor<D> for u128 {
const PRECISION_FACTOR: Self = 10u128.pow(D as u32);
}

impl<const D: u8> PrecisionFactor<D> for i128 {
const PRECISION_FACTOR: Self = 10i128.pow(D as u32);
}
137 changes: 137 additions & 0 deletions src/decimal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::ops::{Add, Div, Mul, Sub};

use num_traits::{ConstOne, One};

use crate::const_traits::PrecisionFactor;

pub type Uint64 = Decimal<u64, 9>;
pub type Uint128 = Decimal<u128, 18>;
pub type Int64 = Decimal<i64, 9>;
pub type Int128 = Decimal<i128, 18>;

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Decimal<I, const D: u8>(pub I);

pub trait Integer<const D: u8>:
PrecisionFactor<D>
+ ConstOne
+ One
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Clone
+ Copy
{
}

impl<I, const D: u8> Integer<D> for I where
I: PrecisionFactor<D>
+ ConstOne
+ One
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Clone
+ Copy
{
}

impl<I, const D: u8> Decimal<I, D>
where
I: Integer<D>,
{
pub const ONE: Decimal<I, D> = Decimal(I::PRECISION_FACTOR);
pub const PRECISION_FACTOR: I = I::PRECISION_FACTOR;
}

impl<I, const D: u8> Add for Decimal<I, D>
where
I: Integer<D>,
{
type Output = Self;

#[inline]
fn add(self, rhs: Self) -> Self::Output {
Decimal(self.0 + rhs.0)
}
}

impl<I, const D: u8> Sub for Decimal<I, D>
where
I: Integer<D>,
{
type Output = Self;

#[inline]
fn sub(self, rhs: Self) -> Self::Output {
Decimal(self.0 - rhs.0)
}
}

impl<I, const D: u8> Mul for Decimal<I, D>
where
I: Integer<D>,
{
type Output = Self;

#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Decimal(self.0 * rhs.0 / I::PRECISION_FACTOR)
}
}

impl<I, const D: u8> Div for Decimal<I, D>
where
I: Integer<D>,
{
type Output = Self;

#[inline]
fn div(self, rhs: Self) -> Self::Output {
Decimal(self.0 * I::PRECISION_FACTOR / rhs.0)
}
}

#[cfg(test)]
mod tests {
use paste::paste;

use super::*;

macro_rules! test_basic_ops {
($variant:ty) => {
paste! {
#[test]
fn [<$variant:lower _add>]() {
assert_eq!(
$variant::ONE + $variant::ONE,
Decimal($variant::PRECISION_FACTOR * 2),
);
}

#[test]
fn [<$variant:lower _sub>]() {
assert_eq!($variant::ONE - $variant::ONE, Decimal(0));
}

#[test]
fn [<$variant:lower _mul>]() {
assert_eq!($variant::ONE * $variant::ONE, $variant::ONE);
}

#[test]
fn [<$variant:lower _div>]() {
assert_eq!($variant::ONE / $variant::ONE, $variant::ONE);
}
}
};
}

test_basic_ops!(Uint64);
test_basic_ops!(Uint128);
test_basic_ops!(Int64);
test_basic_ops!(Int128);
}
74 changes: 3 additions & 71 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,4 @@
use std::ops::{Add, Div, Mul, Sub};
mod const_traits;
mod decimal;

pub const PRECISION_FACTOR: u64 = 10u64.pow(9);

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Decimal64(pub u64);

impl Decimal64 {
pub const ONE: Decimal64 = Decimal64(PRECISION_FACTOR);
}

impl Add for Decimal64 {
type Output = Self;

#[inline]
fn add(self, rhs: Self) -> Self::Output {
Decimal64(self.0 + rhs.0)
}
}

impl Sub for Decimal64 {
type Output = Self;

#[inline]
fn sub(self, rhs: Self) -> Self::Output {
Decimal64(self.0 - rhs.0)
}
}

impl Mul for Decimal64 {
type Output = Self;

#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Decimal64(self.0 * rhs.0 / PRECISION_FACTOR)
}
}

impl Div for Decimal64 {
type Output = Self;

#[inline]
fn div(self, rhs: Self) -> Self::Output {
Decimal64(self.0 * PRECISION_FACTOR / rhs.0)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn add() {
assert_eq!(Decimal64::ONE + Decimal64::ONE, Decimal64(PRECISION_FACTOR * 2));
}

#[test]
fn sub() {
assert_eq!(Decimal64::ONE - Decimal64::ONE, Decimal64(0));
}

#[test]
fn mul() {
assert_eq!(Decimal64::ONE * Decimal64::ONE, Decimal64::ONE);
}

#[test]
fn div() {
assert_eq!(Decimal64::ONE / Decimal64::ONE, Decimal64::ONE);
}
}
pub use decimal::*;

0 comments on commit b0429e8

Please sign in to comment.