Skip to content

Commit 1135c8a

Browse files
committed
Add macro abstraction support
1 parent cb4cc5e commit 1135c8a

File tree

3 files changed

+81
-41
lines changed

3 files changed

+81
-41
lines changed

packages/std/src/errors/std_error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ pub enum CheckedMultiplyFractionalError {
563563

564564
#[error("{0}")]
565565
ConversionOverflow(#[from] ConversionOverflowError),
566+
567+
#[error("{0}")]
568+
Overflow(#[from] OverflowError),
566569
}
567570

568571
#[derive(Error, Debug, PartialEq, Eq)]

packages/std/src/math/fraction.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use serde::{Deserialize, Serialize};
22

3+
use crate::errors::CheckedMultiplyFractionalError;
4+
use crate::Uint512;
5+
36
/// A fraction `p`/`q` with integers `p` and `q`.
47
///
58
/// `p` is called the numerator and `q` is called the denominator.
@@ -37,3 +40,63 @@ impl<T: Clone> Fractional<T> for Fraction<T> {
3740
unimplemented!()
3841
}
3942
}
43+
44+
pub trait FractionMath {
45+
fn checked_mul_floored<F: Fractional<T>, T: Into<Uint512>>(
46+
self,
47+
rhs: F,
48+
) -> Result<Self, CheckedMultiplyFractionalError>
49+
where
50+
Self: Sized;
51+
52+
fn mul_floored<F: Fractional<T>, T: Into<Uint512>>(self, rhs: F) -> Self;
53+
54+
fn checked_mul_ceil<F: Fractional<T> + Clone, T: Into<Uint512>>(
55+
self,
56+
rhs: F,
57+
) -> Result<Self, CheckedMultiplyFractionalError>
58+
where
59+
Self: Sized;
60+
61+
fn mul_ceil<F: Fractional<T> + Clone, T: Into<Uint512>>(self, rhs: F) -> Self;
62+
}
63+
64+
#[macro_export]
65+
macro_rules! fraction_math {
66+
($name:ident) => {
67+
impl FractionMath for $name {
68+
fn checked_mul_floored<F: Fractional<T>, T: Into<Uint512>>(
69+
self,
70+
rhs: F,
71+
) -> Result<Self, CheckedMultiplyFractionalError> {
72+
let res = Uint512::from(self)
73+
.checked_mul(rhs.numerator().into())?
74+
.checked_div(rhs.denominator().into())?;
75+
Ok(res.try_into()?)
76+
}
77+
78+
fn mul_floored<F: Fractional<T>, T: Into<Uint512>>(self, rhs: F) -> Self {
79+
self.checked_mul_floored(rhs).unwrap()
80+
}
81+
82+
fn mul_ceil<F: Fractional<T> + Clone, T: Into<Uint512>>(self, rhs: F) -> Self {
83+
self.checked_mul_ceil(rhs).unwrap()
84+
}
85+
86+
fn checked_mul_ceil<F: Fractional<T> + Clone, T: Into<Uint512>>(
87+
self,
88+
rhs: F,
89+
) -> Result<Self, CheckedMultiplyFractionalError> {
90+
let floor_result = self.checked_mul_floored(rhs.clone())?;
91+
let numerator = rhs.numerator().into();
92+
let denominator = rhs.denominator().into();
93+
if !numerator.checked_rem(denominator)?.is_zero() {
94+
let ceil_result = Uint512::one().checked_add(floor_result.into())?;
95+
Ok(ceil_result.try_into()?)
96+
} else {
97+
Ok(floor_result)
98+
}
99+
}
100+
}
101+
};
102+
}

packages/std/src/math/uint128.rs

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
use forward_ref::{forward_ref_binop, forward_ref_op_assign};
2-
use schemars::JsonSchema;
3-
use serde::{de, ser, Deserialize, Deserializer, Serialize};
41
use std::fmt::{self};
52
use std::ops::{
63
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shr, ShrAssign, Sub, SubAssign,
74
};
85
use std::str::FromStr;
96

7+
use forward_ref::{forward_ref_binop, forward_ref_op_assign};
8+
use schemars::JsonSchema;
9+
use serde::{de, ser, Deserialize, Deserializer, Serialize};
10+
11+
use crate::errors::CheckedMultiplyFractionalError;
1012
use crate::errors::{
11-
CheckedMultiplyFractionalError, CheckedMultiplyRatioError, DivideByZeroError, OverflowError,
12-
OverflowOperation, StdError,
13+
CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError,
1314
};
14-
use crate::{ConversionOverflowError, Fractional, Uint256, Uint64};
15+
use crate::math::fraction::FractionMath;
16+
use crate::{fraction_math, ConversionOverflowError, Fractional, Uint256, Uint512, Uint64};
1517

1618
/// A thin wrapper around u128 that is using strings for JSON encoding/decoding,
1719
/// such that the full u128 range can be used for clients that convert JSON numbers to floats,
@@ -137,37 +139,6 @@ impl Uint128 {
137139
.unwrap()
138140
}
139141

140-
pub fn mul_floored<F: Fractional<T>, T: Into<u128>>(self, rhs: F) -> Self {
141-
self.checked_mul_floored(rhs).unwrap()
142-
}
143-
144-
pub fn checked_mul_floored<F: Fractional<T>, T: Into<u128>>(
145-
self,
146-
rhs: F,
147-
) -> Result<Self, CheckedMultiplyFractionalError> {
148-
let res = self
149-
.full_mul(rhs.numerator())
150-
.checked_div(Uint256::from(rhs.denominator().into()))?;
151-
Ok(res.try_into()?)
152-
}
153-
154-
pub fn mul_ceil<F: Fractional<T> + Clone, T: Into<u128>>(self, rhs: F) -> Self {
155-
self.checked_mul_ceil(rhs).unwrap()
156-
}
157-
158-
pub fn checked_mul_ceil<F: Fractional<T> + Clone, T: Into<u128>>(
159-
self,
160-
rhs: F,
161-
) -> Result<Self, CheckedMultiplyFractionalError> {
162-
let mut result = self.checked_mul_floored(rhs.clone())?;
163-
let numerator = Uint256::from(rhs.numerator().into());
164-
let denominator = Uint256::from(rhs.denominator().into());
165-
if !numerator.checked_rem(denominator)?.is_zero() {
166-
result += Uint128::one();
167-
};
168-
Ok(result)
169-
}
170-
171142
pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
172143
self.0
173144
.checked_add(other.0)
@@ -262,6 +233,8 @@ impl Uint128 {
262233
}
263234
}
264235

236+
fraction_math!(Uint128);
237+
265238
// `From<u{128,64,32,16,8}>` is implemented manually instead of
266239
// using `impl<T: Into<u128>> From<T> for Uint128` because
267240
// of the conflict with `TryFrom<&str>` as described here
@@ -569,11 +542,12 @@ impl PartialEq<Uint128> for &Uint128 {
569542

570543
#[cfg(test)]
571544
mod tests {
572-
use super::*;
573545
use crate::errors::CheckedMultiplyFractionalError::{ConversionOverflow, DivideByZero};
574-
use crate::math::fraction::Fraction;
546+
use crate::math::fraction::{Fraction, FractionMath};
575547
use crate::{from_slice, to_vec, Decimal};
576548

549+
use super::*;
550+
577551
#[test]
578552
fn size_of_works() {
579553
assert_eq!(std::mem::size_of::<Uint128>(), 16);
@@ -1115,7 +1089,7 @@ mod tests {
11151089
assert_eq!(
11161090
Uint128::MAX.checked_mul_floored(fraction),
11171091
Err(ConversionOverflow(ConversionOverflowError {
1118-
source_type: "Uint256",
1092+
source_type: "Uint512",
11191093
target_type: "Uint128",
11201094
value: "893241213167463466591358344508391555069".to_string()
11211095
})),
@@ -1181,7 +1155,7 @@ mod tests {
11811155
assert_eq!(
11821156
Uint128::MAX.checked_mul_ceil(fraction),
11831157
Err(ConversionOverflow(ConversionOverflowError {
1184-
source_type: "Uint256",
1158+
source_type: "Uint512",
11851159
target_type: "Uint128",
11861160
value: "893241213167463466591358344508391555069".to_string()
11871161
})),

0 commit comments

Comments
 (0)