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