From cf54a9138b672c373ce7769ad1f18518a8c17254 Mon Sep 17 00:00:00 2001 From: Xiliang Chen <xlchen1291@gmail.com> Date: Wed, 18 Dec 2019 21:57:43 +0800 Subject: [PATCH] add helper methods to FixedU128 (#64) --- utilities/src/fixed128.rs | 56 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/utilities/src/fixed128.rs b/utilities/src/fixed128.rs index d611c11..f3cd002 100644 --- a/utilities/src/fixed128.rs +++ b/utilities/src/fixed128.rs @@ -2,7 +2,7 @@ use codec::{Decode, Encode}; use primitives::U256; use rstd::convert::{Into, TryFrom, TryInto}; use sp_runtime::{ - traits::{Bounded, Saturating}, + traits::{Bounded, Saturating, UniqueSaturatedInto}, Perbill, Percent, Permill, Perquintill, }; @@ -38,9 +38,15 @@ impl FixedU128 { /// Creates self from a rational number. Equal to `n/d`. /// /// Note that this might be lossy. - pub fn from_rational(n: u128, d: u128) -> Self { + pub fn from_rational<N: UniqueSaturatedInto<u128>>(n: N, d: N) -> Self { + // this should really be `N: Into<U256>` or else might give wrong result + // TODO: Should have a better way to enforce this requirement + let n = n.unique_saturated_into(); + let n = U256::from(n); + let d = d.unique_saturated_into(); + let d = U256::from(d); Self( - (U256::from(n).saturating_mul(U256::from(DIV)) / U256::from(d).max(U256::one())) + (n.saturating_mul(DIV.into()) / d.max(U256::one())) .try_into() .unwrap_or_else(|_| Bounded::max_value()), ) @@ -117,6 +123,14 @@ impl FixedU128 { None } + /// Checked mul for int type `N`. + pub fn saturating_mul_int<N>(&self, other: &N) -> N + where + N: Copy + TryFrom<u128> + TryInto<u128> + Bounded, + { + self.checked_mul_int(other).unwrap_or_else(Bounded::max_value) + } + /// Checked div for int type `N`. pub fn checked_div_int<N>(&self, other: &N) -> Option<N> where @@ -132,6 +146,14 @@ impl FixedU128 { None } + + pub fn zero() -> Self { + Self(0) + } + + pub fn is_zero(&self) -> bool { + self.0 == 0 + } } impl Saturating for FixedU128 { @@ -178,7 +200,7 @@ macro_rules! impl_perthing_into_fixed_u128 { ($perthing:ty) => { impl Into<FixedU128> for $perthing { fn into(self) -> FixedU128 { - FixedU128::from_rational(self.deconstruct().into(), <$perthing>::accuracy().into()) + FixedU128::from_rational(self.deconstruct(), <$perthing>::accuracy()) } } }; @@ -241,6 +263,32 @@ mod tests { assert_eq!(a.checked_mul_int::<i32>(&b), Some(10)); } + #[test] + fn saturating_mul_int_works() { + let a = FixedU128::from_rational(10, 1); + let b = u32::max_value() / 5; + assert_eq!(a.saturating_mul_int(&b), u32::max_value()); + + let a = FixedU128::from_rational(3, 1); + let b = 100u8; + assert_eq!(a.saturating_mul_int(&b), 255u8); + + let a = FixedU128::from_rational(10, 1); + let b = 123; + assert_eq!(a.saturating_mul_int(&b), 1230); + } + + #[test] + fn zero_works() { + assert_eq!(FixedU128::zero(), FixedU128::from_natural(0)); + } + + #[test] + fn is_zero_works() { + assert!(FixedU128::zero().is_zero()); + assert!(!FixedU128::from_natural(1).is_zero()); + } + #[test] fn checked_div_with_zero_should_be_none() { let a = FixedU128::from_natural(1); -- GitLab