From 8708b4f20e04150ce5c2c7adc5f81ba5ab952c78 Mon Sep 17 00:00:00 2001 From: wangjj9219 <183318287@qq.com> Date: Tue, 9 Jun 2020 13:03:09 +0800 Subject: [PATCH] Remove unnessasery implementation (#208) * remove LinkedMap and FixedU128 implemention * bump version --- README.md | 2 +- auction/Cargo.toml | 4 +- authority/Cargo.toml | 4 +- benchmarking/Cargo.toml | 2 +- currencies/Cargo.toml | 4 +- gradually-update/Cargo.toml | 6 +- gradually-update/src/tests.rs | 3 +- oracle/Cargo.toml | 6 +- oracle/rpc/Cargo.toml | 2 +- oracle/rpc/runtime-api/Cargo.toml | 2 +- prices/Cargo.toml | 16 +- prices/src/lib.rs | 6 +- prices/src/tests.rs | 2 +- schedule-update/Cargo.toml | 4 +- tokens/Cargo.toml | 6 +- traits/Cargo.toml | 2 +- utilities/Cargo.toml | 11 +- utilities/src/fixed_u128.rs | 1157 ----------------------------- utilities/src/lib.rs | 5 - utilities/src/linked_item.rs | 429 ----------- vesting/Cargo.toml | 2 +- 21 files changed, 29 insertions(+), 1646 deletions(-) delete mode 100644 utilities/src/fixed_u128.rs delete mode 100644 utilities/src/linked_item.rs diff --git a/README.md b/README.md index b1f74b3..a328480 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The Open Runtime Module Library (ORML) is a community maintained collection of S - [orml-traits](./traits) - Shared traits including `BasicCurrency`, `MultiCurrency`, `Auction` and more. - [orml-utilities](./utilities) - - Various utilities including `FixedU128` and `LinkedList`. + - Various utilities including `OrderSet`. - [orml-tokens](./tokens) - Fungible tokens module that implements `MultiCurrency` trait. - [orml-currencies](./currencies) diff --git a/auction/Cargo.toml b/auction/Cargo.toml index dc5ae54..4acb9c1 100644 --- a/auction/Cargo.toml +++ b/auction/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-auction" description = "Auction module that implements `Auction` trait." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/auction" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Acala Developers"] edition = "2018" @@ -17,7 +17,7 @@ sp-std = { version = "2.0.0-rc3", default-features = false } frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-core = { version = "2.0.0-rc3", default-features = false } diff --git a/authority/Cargo.toml b/authority/Cargo.toml index 7a744a3..94e45c6 100644 --- a/authority/Cargo.toml +++ b/authority/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-authority" description = "Utility pallet to perform ROOT calls in a PoA network" repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/auction" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Acala Developers"] edition = "2018" @@ -17,7 +17,7 @@ sp-std = { version = "2.0.0-rc3", default-features = false } frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-core = { version = "2.0.0-rc3", default-features = false } diff --git a/benchmarking/Cargo.toml b/benchmarking/Cargo.toml index dd4b719..93f0bfe 100644 --- a/benchmarking/Cargo.toml +++ b/benchmarking/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-benchmarking" description = "Provide macro to benchmark Substrate runtime." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/benchmarking" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" diff --git a/currencies/Cargo.toml b/currencies/Cargo.toml index f5a6827..110ed5a 100644 --- a/currencies/Cargo.toml +++ b/currencies/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-currencies" description = "Provide `MultiCurrency` implementation using `pallet-balances` and `orml-tokens` module." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/currencies" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" @@ -17,7 +17,7 @@ sp-std = { version = "2.0.0-rc3", default-features = false } frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-core = { version = "2.0.0-rc3", default-features = false } diff --git a/gradually-update/Cargo.toml b/gradually-update/Cargo.toml index 8d01451..f891650 100644 --- a/gradually-update/Cargo.toml +++ b/gradually-update/Cargo.toml @@ -3,13 +3,12 @@ name = "orml-gradually-update" description = "Provides way to adjust numeric parameter gradually over a period of time." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/gradually-update" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" [dependencies] codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false } - frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } sp-io = { version = "2.0.0-rc3", default-features = false } @@ -17,9 +16,6 @@ sp-std = { version = "2.0.0-rc3", default-features = false } sp-core = { version = "2.0.0-rc3", default-features = false } sp-runtime = { version = "2.0.0-rc3", default-features = false } -[dev-dependencies] -orml-utilities = { path = "../utilities", default-features = false } - [features] default = ["std"] std = [ diff --git a/gradually-update/src/tests.rs b/gradually-update/src/tests.rs index 635c5f8..6565a94 100644 --- a/gradually-update/src/tests.rs +++ b/gradually-update/src/tests.rs @@ -5,8 +5,7 @@ use super::*; use frame_support::{assert_noop, assert_ok, traits::OnFinalize}; use mock::{ExtBuilder, GraduallyUpdateModule, Origin, Runtime, System, TestEvent}; -use orml_utilities::{FixedU128, FixedUnsignedNumber}; -use sp_runtime::Permill; +use sp_runtime::{FixedPointNumber, FixedU128, Permill}; fn storage_set(key: &Vec<u8>, value: &Vec<u8>) { storage::unhashed::put(key, value); diff --git a/oracle/Cargo.toml b/oracle/Cargo.toml index 405944d..4485583 100644 --- a/oracle/Cargo.toml +++ b/oracle/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-oracle" description = "Oracle module that makes off-chain data available on-chain." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/oracle" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" @@ -19,8 +19,8 @@ sp-std = { version = "2.0.0-rc3", default-features = false } frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } -orml-utilities = { path = "../utilities", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } +orml-utilities = { path = "../utilities", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-core = { version = "2.0.0-rc3", default-features = false } diff --git a/oracle/rpc/Cargo.toml b/oracle/rpc/Cargo.toml index b7b860a..6a435f9 100644 --- a/oracle/rpc/Cargo.toml +++ b/oracle/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orml-oracle-rpc" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" diff --git a/oracle/rpc/runtime-api/Cargo.toml b/oracle/rpc/runtime-api/Cargo.toml index e3d1ef1..1ccba8e 100644 --- a/oracle/rpc/runtime-api/Cargo.toml +++ b/oracle/rpc/runtime-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orml-oracle-rpc-runtime-api" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" diff --git a/prices/Cargo.toml b/prices/Cargo.toml index a39a144..5dc9a72 100644 --- a/prices/Cargo.toml +++ b/prices/Cargo.toml @@ -3,38 +3,26 @@ name = "orml-prices" description = "Provide basic asset price abstraction." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/prices" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Acala Developers"] edition = "2018" [dependencies] serde = { version = "1.0.111", optional = true } -codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false } sp-runtime = { version = "2.0.0-rc3", default-features = false } -sp-io = { version = "2.0.0-rc3", default-features = false } sp-std = { version = "2.0.0-rc3", default-features = false } - frame-support = { version = "2.0.0-rc3", default-features = false } -frame-system = { version = "2.0.0-rc3", default-features = false } - -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } -orml-utilities = { path = "../utilities", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] -sp-core = { version = "2.0.0-rc3", default-features = false } - clear_on_drop = { version = "0.2.4", features = ["no_cc"] } # https://github.com/paritytech/substrate/issues/4179 [features] default = ["std"] std = [ "serde", - "codec/std", - "sp-io/std", "sp-runtime/std", "sp-std/std", "frame-support/std", - "frame-system/std", "orml-traits/std", - "orml-utilities/std", ] diff --git a/prices/src/lib.rs b/prices/src/lib.rs index 8944e79..5e9455d 100644 --- a/prices/src/lib.rs +++ b/prices/src/lib.rs @@ -2,8 +2,10 @@ use frame_support::Parameter; use orml_traits::{DataProvider, PriceProvider}; -use orml_utilities::FixedU128; -use sp_runtime::traits::{CheckedDiv, MaybeSerializeDeserialize, Member}; +use sp_runtime::{ + traits::{CheckedDiv, MaybeSerializeDeserialize, Member}, + FixedU128, +}; use sp_std::marker::PhantomData; pub type Price = FixedU128; diff --git a/prices/src/tests.rs b/prices/src/tests.rs index 997d2cd..2b68257 100644 --- a/prices/src/tests.rs +++ b/prices/src/tests.rs @@ -3,7 +3,7 @@ #![cfg(test)] use super::*; -use orml_utilities::FixedUnsignedNumber; +use sp_runtime::FixedPointNumber; pub struct MockDataProvider; impl DataProvider<u32, Price> for MockDataProvider { diff --git a/schedule-update/Cargo.toml b/schedule-update/Cargo.toml index d036d9f..e975d1b 100644 --- a/schedule-update/Cargo.toml +++ b/schedule-update/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-schedule-update" description = "Provides way to schedule a call to be dispatched at later block." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/schedule-update" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" @@ -14,7 +14,7 @@ frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } sp-std = { version = "2.0.0-rc3", default-features = false } sp-runtime = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-io = { version = "2.0.0-rc3", default-features = false } diff --git a/tokens/Cargo.toml b/tokens/Cargo.toml index 2816a2d..6709d9b 100644 --- a/tokens/Cargo.toml +++ b/tokens/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-tokens" description = "Fungible tokens module that implements `MultiCurrency` trait." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/tokens" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" @@ -17,8 +17,7 @@ sp-std = { version = "2.0.0-rc3", default-features = false } frame-support = { version = "2.0.0-rc3", default-features = false } frame-system = { version = "2.0.0-rc3", default-features = false } -orml-traits = { path = "../traits", version = "0.1.2-dev", default-features = false } -orml-utilities = { path = "../utilities", version = "0.1.2-dev", default-features = false } +orml-traits = { path = "../traits", version = "0.1.3-dev", default-features = false } [dev-dependencies] sp-core = { version = "2.0.0-rc3", default-features = false } @@ -36,5 +35,4 @@ std = [ "frame-support/std", "frame-system/std", "orml-traits/std", - "orml-utilities/std", ] diff --git a/traits/Cargo.toml b/traits/Cargo.toml index 60bd669..df42fcc 100644 --- a/traits/Cargo.toml +++ b/traits/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-traits" description = "Shared traits including `BasicCurrency`, `MultiCurrency`, `Auction` and more." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/traits" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml index 98d127e..95f6a46 100644 --- a/utilities/Cargo.toml +++ b/utilities/Cargo.toml @@ -3,21 +3,15 @@ name = "orml-utilities" description = "Various utilities including `FixedU128` and `LinkedList`." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/utilities" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" [dependencies] serde = { version = "1.0.111", optional = true } codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false } -sp-core = { version = "2.0.0-rc3", default-features = false } sp-runtime = { version = "2.0.0-rc3", default-features = false } -sp-io = { version = "2.0.0-rc3", default-features = false } sp-std = { version = "2.0.0-rc3", default-features = false } -sp-arithmetic= { version = "2.0.0-rc3", default-features = false } - -frame-system = { version = "2.0.0-rc3", default-features = false } -frame-support = { version = "2.0.0-rc3", default-features = false } [dev-dependencies] serde_json = "1.0.53" @@ -30,8 +24,5 @@ std = [ "serde", "codec/std", "sp-runtime/std", - "sp-io/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] diff --git a/utilities/src/fixed_u128.rs b/utilities/src/fixed_u128.rs deleted file mode 100644 index 2b3adf0..0000000 --- a/utilities/src/fixed_u128.rs +++ /dev/null @@ -1,1157 +0,0 @@ -use codec::{CompactAs, Decode, Encode}; -use sp_arithmetic::traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero}; -use sp_core::U256; -use sp_runtime::{ - traits::{Bounded, Saturating, UniqueSaturatedInto}, - PerThing, Perbill, Percent, Permill, Perquintill, -}; -use sp_std::{ - convert::{Into, TryFrom, TryInto}, - fmt::{self, Debug}, - ops::{self, Add, Div, Mul, Sub}, -}; - -#[cfg(feature = "std")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; - -/// An unsigned fixed point number. Can hold any value in the range [0, 340_282_366_920_938_463_464] -/// with fixed point accuracy of 10 ** 18. -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, CompactAs)] -pub struct FixedU128(u128); - -const DIV: u128 = 1_000_000_000_000_000_000; - -/// Integer types that can be used to interact with `FixedPointNumber` implementations. -pub trait FixedPointOperand: - Copy - + Clone - + Bounded - + Zero - + Saturating - + PartialOrd - + UniqueSaturatedInto<u128> - + TryFrom<u128> - + TryInto<u128> - + TryFrom<U256> -{ -} - -impl FixedPointOperand for i128 {} -impl FixedPointOperand for u128 {} -impl FixedPointOperand for i64 {} -impl FixedPointOperand for u64 {} -impl FixedPointOperand for i32 {} -impl FixedPointOperand for u32 {} -impl FixedPointOperand for i16 {} -impl FixedPointOperand for u16 {} -impl FixedPointOperand for i8 {} -impl FixedPointOperand for u8 {} - -pub trait FixedUnsignedNumber: - Sized - + Copy - + Default - + fmt::Debug - + Saturating - + Bounded - + Eq - + PartialEq - + Ord - + PartialOrd - + CheckedSub - + CheckedAdd - + CheckedMul - + CheckedDiv - + Add - + Sub - + Div - + Mul - + Zero - + One -{ - type Inner: Debug + One + CheckedMul + CheckedDiv + FixedPointOperand + Into<U256> + Into<u128>; - - /// Precision of this fixed point implementation. It should be a power of `10`. - const DIV: Self::Inner; - - /// Precision of this fixed point implementation. - fn accuracy() -> Self::Inner { - Self::DIV - } - - /// Create `self` from a natural number. - /// - /// Note that this might be lossy. - fn from_natural(int: Self::Inner) -> Self; - - /// Builds this type from an integer number. - fn from_inner(int: Self::Inner) -> Self; - - /// Consumes `self` and returns the inner raw value. - fn into_inner(self) -> Self::Inner; - - /// Creates self from an integer number `int`. - /// - /// Returns `Self::max` or `Self::min` if `int` exceeds accuracy. - fn saturating_from_integer<N: UniqueSaturatedInto<Self::Inner> + PartialOrd + Zero>(int: N) -> Self { - if int < N::zero() { - return Self::min_value(); - } - - Self::from_inner(int.unique_saturated_into().saturating_mul(Self::DIV)) - } - - /// Creates `self` from an integer number `int`. - /// - /// Returns `None` if `int` exceeds accuracy. - fn checked_from_integer(int: Self::Inner) -> Option<Self> { - int.checked_mul(&Self::DIV).map(Self::from_inner) - } - - /// Creates `self` from a rational number. Equal to `n / d`. - /// - /// Panics if `d = 0`. Returns `Self::max` or `Self::min` if `n / d` exceeds accuracy. - fn saturating_from_rational<N: FixedPointOperand, D: FixedPointOperand>(n: N, d: D) -> Self { - if d == D::zero() { - panic!("attempt to divide by zero") - } - Self::checked_from_rational(n, d).unwrap_or_else(|| to_bound(n, d)) - } - - /// Creates `self` from a rational number. Equal to `n / d`. - /// - /// Returns `None` if `d == 0` or `n / d` exceeds accuracy. - fn checked_from_rational<N: FixedPointOperand, D: FixedPointOperand>(n: N, d: D) -> Option<Self> { - if d == D::zero() { - return None; - } - - // 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 d = d.unique_saturated_into(); - // let d = U256::from(d); - - let n: u128 = (n).try_into().ok()?; - let n = U256::from(n); - let d: u128 = (d).try_into().ok()?; - let d = U256::from(d); - - n.checked_mul(U256::from(Self::DIV.unique_saturated_into())) - .and_then(|n| n.checked_div(d)) - .and_then(|n| n.try_into().ok()) - .map(Self::from_inner) - } - - /// Checked mul for int type `N`. Equal to `self * n`. - /// - /// Returns `None` if the result does not fit in `N`. - fn checked_mul_int<N: FixedPointOperand>(&self, other: N) -> Option<N> { - let lhs: U256 = self.into_inner().into(); - let rhs: u128 = other.try_into().ok()?; - let rhs: U256 = U256::from(rhs); - - lhs.checked_mul(rhs) - .and_then(|n| n.checked_div(U256::from(Self::DIV.unique_saturated_into()))) - .and_then(|n| n.try_into().ok()) - .and_then(from_u128) - } - - /// Saturating multiplication for integer type `N`. Equal to `self * n`. - /// - /// Returns `N::min` or `N::max` if the result does not fit in `N`. - fn saturating_mul_int<N: FixedPointOperand>(self, n: N) -> N { - self.checked_mul_int(n) - .unwrap_or_else(|| to_bound(self.into_inner(), n)) - } - - /// Checked division for integer type `N`. Equal to `self / d`. - /// - /// Returns `None` if the result does not fit in `N` or `d == 0`. - fn checked_div_int<N: FixedPointOperand>(&self, other: N) -> Option<N> { - let lhs: u128 = self.into_inner().into(); - let rhs: u128 = other.try_into().ok()?; - - lhs.checked_div(rhs) - .and_then(|n| n.checked_div(Self::DIV.unique_saturated_into())) - .and_then(from_u128) - } - - /// Saturating division for integer type `N`. Equal to `self / d`. - /// - /// Panics if `d == 0`. Returns `N::min` or `N::max` if the result does not fit in `N`. - fn saturating_div_int<N: FixedPointOperand>(self, d: N) -> N { - if d == N::zero() { - panic!("attempt to divide by zero") - } - self.checked_div_int(d) - .unwrap_or_else(|| to_bound(self.into_inner(), d)) - } - - /// Saturating multiplication for integer type `N`, adding the result back. - /// Equal to `self * n + n`. - /// - /// Returns `N::min` or `N::max` if the multiplication or final result does not fit in `N`. - fn saturating_mul_acc_int<N: FixedPointOperand>(self, n: N) -> N { - self.saturating_mul_int(n).saturating_add(n) - } - - /// Takes the reciprocal (inverse). Equal to `1 / self`. - /// - /// Returns `None` if `self = 0`. - fn reciprocal(self) -> Option<Self> { - Self::one().checked_div(&self) - } - - /// Returns the integer part. - fn trunc(self) -> Self { - self.into_inner() - .checked_div(&Self::DIV) - .expect("panics only if DIV is zero, DIV is not zero; qed") - .checked_mul(&Self::DIV) - .map(Self::from_inner) - .expect("can not overflow since fixed number is >= integer part") - } - - /// Returns the fractional part. - /// - /// Note: the returned fraction will be non-negative for negative numbers, - /// except in the case where the integer part is zero. - fn frac(self) -> Self { - let integer = self.trunc(); - - self.saturating_sub(integer) - } - - /// Returns the smallest integer greater than or equal to a number. - /// - /// Saturates to `Self::max` (truncated) if the result does not fit. - fn ceil(self) -> Self { - if self.is_zero() { - return self.trunc(); - } - self.saturating_add(Self::one()).trunc() - } - - /// Returns the largest integer less than or equal to a number. - /// - /// Saturates to `Self::min` (truncated) if the result does not fit. - fn floor(self) -> Self { - self.trunc() - } - - /// Returns the number rounded to the nearest integer. Rounds half-way cases away from 0.0. - /// - /// Saturates to `Self::min` or `Self::max` (truncated) if the result does not fit. - fn round(self) -> Self { - let n = self.frac().saturating_mul(Self::saturating_from_integer(10)); - if n < Self::saturating_from_integer(5) { - self.floor() - } else { - self.ceil() - } - } -} - -impl FixedUnsignedNumber for FixedU128 { - type Inner = u128; - - const DIV: Self::Inner = DIV; - - fn from_natural(n: Self::Inner) -> Self { - Self::from_inner(n.saturating_mul(Self::DIV)) - } - - fn from_inner(n: Self::Inner) -> Self { - Self(n) - } - - fn into_inner(self) -> Self::Inner { - self.0 - } -} - -/// Returns `R::max` if the sign of `n * m` is positive, `R::min` otherwise. -fn to_bound<N: FixedPointOperand, D: FixedPointOperand, R: Bounded + Zero>(n: N, m: D) -> R { - if n < N::zero() { - return R::zero(); - } - if m < D::zero() { - return R::zero(); - } - - R::max_value() -} - -fn from_u128<N: FixedPointOperand>(n: u128) -> Option<N> { - let r: N = n.try_into().ok()?; - Some(r) -} - -impl Zero for FixedU128 { - fn zero() -> Self { - Self(0) - } - - fn is_zero(&self) -> bool { - self.0 == 0 - } -} - -impl One for FixedU128 { - fn one() -> Self { - Self(DIV) - } - - fn is_one(&self) -> bool { - self.0 == DIV - } -} - -impl Saturating for FixedU128 { - fn saturating_add(self, rhs: Self) -> Self { - Self(self.0.saturating_add(rhs.0)) - } - - fn saturating_mul(self, rhs: Self) -> Self { - Self( - (U256::from(self.0).saturating_mul(U256::from(rhs.0)) / U256::from(DIV)) - .try_into() - .unwrap_or_else(|_| Bounded::max_value()), - ) - } - - fn saturating_sub(self, rhs: Self) -> Self { - Self(self.0.saturating_sub(rhs.0)) - } - - fn saturating_pow(self, exp: usize) -> Self { - if exp == 0 { - return Self::saturating_from_integer(1); - } - - let exp = exp as u64; - let msb_pos = 64 - exp.leading_zeros(); - - let mut result = Self::saturating_from_integer(1); - let mut pow_val = self; - for i in 0..msb_pos { - if ((1 << i) & exp) > 0 { - result = result.saturating_mul(pow_val); - } - pow_val = pow_val.saturating_mul(pow_val); - } - result - } -} - -impl ops::Add for FixedU128 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl ops::Sub for FixedU128 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - -impl ops::Mul for FixedU128 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - self.checked_mul(&rhs) - .unwrap_or_else(|| panic!("attempt to multiply with overflow")) - } -} - -impl ops::Div for FixedU128 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - if rhs.0 == 0 { - panic!("attempt to divide by zero") - } - - self.checked_div(&rhs) - .unwrap_or_else(|| panic!("attempt to divide with overflow")) - } -} - -impl CheckedAdd for FixedU128 { - fn checked_add(&self, rhs: &Self) -> Option<Self> { - self.0.checked_add(rhs.0).map(Self) - } -} - -impl CheckedSub for FixedU128 { - fn checked_sub(&self, rhs: &Self) -> Option<Self> { - self.0.checked_sub(rhs.0).map(Self) - } -} - -impl CheckedMul for FixedU128 { - fn checked_mul(&self, rhs: &Self) -> Option<Self> { - U256::from(self.0) - .checked_mul(U256::from(rhs.0)) - .and_then(|n| n.checked_div(U256::from(DIV))) - .and_then(|n| TryInto::<u128>::try_into(n).ok()) - .map(Self) - } -} - -impl CheckedDiv for FixedU128 { - fn checked_div(&self, rhs: &Self) -> Option<Self> { - U256::from(self.0) - .checked_mul(U256::from(DIV)) - .and_then(|n| n.checked_div(U256::from(rhs.0))) - .and_then(|n| TryInto::<u128>::try_into(n).ok()) - .map(Self) - } -} - -impl Bounded for FixedU128 { - fn max_value() -> Self { - Self(u128::max_value()) - } - - fn min_value() -> Self { - Self(0u128) - } -} - -impl fmt::Debug for FixedU128 { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let fractional = format!("{:0>18}", self.0 % DIV); - write!(f, "FixedU128({}.{})", self.0 / DIV, fractional) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Display for FixedU128 { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", self.0) - } -} - -#[cfg(feature = "std")] -impl sp_std::str::FromStr for FixedU128 { - type Err = &'static str; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - let inner: u128 = s.parse().map_err(|_| "invalid string input for fixed u128")?; - Ok(Self::from_inner(inner)) - } -} - -impl From<u128> for FixedU128 { - fn from(n: u128) -> Self { - Self::saturating_from_integer(n) - } -} - -impl From<Permill> for FixedU128 { - fn from(val: Permill) -> Self { - FixedU128::saturating_from_rational(val.deconstruct(), Permill::ACCURACY) - } -} - -impl From<Percent> for FixedU128 { - fn from(val: Percent) -> Self { - FixedU128::saturating_from_rational(val.deconstruct(), Percent::ACCURACY) - } -} - -impl From<Perbill> for FixedU128 { - fn from(val: Perbill) -> Self { - FixedU128::saturating_from_rational(val.deconstruct(), Perbill::ACCURACY) - } -} - -impl From<Perquintill> for FixedU128 { - fn from(val: Perquintill) -> Self { - FixedU128::saturating_from_rational(val.deconstruct(), Perquintill::ACCURACY) - } -} - -#[cfg(feature = "std")] -impl FixedU128 { - fn u128_str(&self) -> String { - format!("{}", &self.0) - } - - fn try_from_u128_str(s: &str) -> Result<Self, &'static str> { - let parts: u128 = s.parse().map_err(|_| "invalid string input")?; - Ok(Self::from_inner(parts)) - } -} - -// Manual impl `Serialize` as serde_json does not support u128. -// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed. -#[cfg(feature = "std")] -impl Serialize for FixedU128 { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - serializer.serialize_str(&self.u128_str()) - } -} - -// Manual impl `Serialize` as serde_json does not support u128. -// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed. -#[cfg(feature = "std")] -impl<'de> Deserialize<'de> for FixedU128 { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - FixedU128::try_from_u128_str(&s).map_err(de::Error::custom) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::{Perbill, Percent, Permill, Perquintill}; - - fn max() -> FixedU128 { - FixedU128::from_inner(u128::max_value()) - } - #[test] - fn to_bound_works() { - let a = 1i32; - let b = 1i32; - - // Pos + Pos => Max. - assert_eq!(to_bound::<_, _, i32>(a, b), i32::max_value()); - - let a = -1i32; - let b = -1i32; - - // Neg + Neg => 0. - assert_eq!(to_bound::<_, _, i32>(a, b), 0); - - let a = 1i32; - let b = -1i32; - - // Pos + Neg => 0. - assert_eq!(to_bound::<_, _, i32>(a, b), 0); - - let a = -1i32; - let b = 1i32; - - // Neg + Pos => 0. - assert_eq!(to_bound::<_, _, i32>(a, b), 0); - - let a = 1i32; - let b = -1i32; - - // Pos + Neg => Min (unsigned). - assert_eq!(to_bound::<_, _, u32>(a, b), 0); - } - - #[test] - fn fixed128_semantics() { - assert_eq!( - FixedU128::saturating_from_rational(5, 2).into_inner(), - 5 * 1_000_000_000_000_000_000 / 2 - ); - assert_eq!( - FixedU128::saturating_from_rational(5, 2), - FixedU128::saturating_from_rational(10, 4) - ); - - // biggest value that can be created. - assert_ne!(max(), FixedU128::from_natural(340_282_366_920_938_463_463)); - assert_eq!(max(), FixedU128::from_natural(340_282_366_920_938_463_464)); - } - - #[test] - fn fixed128_operation() { - let a = FixedU128::from_natural(2); - let b = FixedU128::from_natural(1); - assert_eq!(a.checked_add(&b), Some(FixedU128::from_natural(1 + 2))); - assert_eq!(a.checked_sub(&b), Some(FixedU128::from_natural(2 - 1))); - assert_eq!(a.checked_mul(&b), Some(FixedU128::from_natural(1 * 2))); - assert_eq!(a.checked_div(&b), Some(FixedU128::saturating_from_rational(2, 1))); - - let a = FixedU128::saturating_from_rational(5, 2); - let b = FixedU128::saturating_from_rational(3, 2); - assert_eq!(a.checked_add(&b), Some(FixedU128::saturating_from_rational(8, 2))); - assert_eq!(a.checked_sub(&b), Some(FixedU128::saturating_from_rational(2, 2))); - assert_eq!(a.checked_mul(&b), Some(FixedU128::saturating_from_rational(15, 4))); - assert_eq!(a.checked_div(&b), Some(FixedU128::saturating_from_rational(10, 6))); - - let a = FixedU128::from_natural(120); - let b = 2i32; - assert_eq!(a.checked_div_int::<i32>(b), Some(60)); - - let a = FixedU128::saturating_from_rational(20, 1); - let b = 2i32; - assert_eq!(a.checked_div_int::<i32>(b), Some(10)); - - let a = FixedU128::from_natural(120); - let b = 2i32; - assert_eq!(a.checked_mul_int::<i32>(b), Some(240)); - - let a = FixedU128::saturating_from_rational(1, 2); - let b = 20i32; - assert_eq!(a.checked_mul_int::<i32>(b), Some(10)); - } - - #[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 op_checked_add_overflow_should_be_none() { - let a = FixedU128::max_value(); - let b = 1.into(); - assert!(a.checked_add(&b).is_none()); - } - - #[test] - #[should_panic(expected = "attempt to add with overflow")] - fn op_add_overflow_should_panic() { - let a = FixedU128::max_value(); - let b = 1.into(); - let _c = a + b; - } - - #[test] - fn op_add_works() { - let a = FixedU128::saturating_from_rational(1, 2); - let b = FixedU128::saturating_from_rational(5, 3); - assert_eq!(FixedU128::saturating_from_rational(13, 6), a + b); - } - - #[test] - fn op_checked_sub_underflow_should_be_none() { - let a = FixedU128::min_value(); - let b = 1.into(); - assert!(a.checked_sub(&b).is_none()); - } - - #[test] - #[should_panic(expected = "attempt to subtract with overflow")] - fn op_sub_underflow_should_panic() { - let a = FixedU128::min_value(); - let b = 1.into(); - let _c = a - b; - } - - #[test] - fn op_sub_works() { - let a = FixedU128::saturating_from_rational(1, 2); - let b = FixedU128::saturating_from_rational(5, 3); - assert_eq!(FixedU128::saturating_from_rational(7, 6), b - a); - } - - #[test] - fn op_checked_mul_overflow_should_be_none() { - let a = FixedU128::max_value(); - let b = 2.into(); - assert!(a.checked_mul(&b).is_none()); - } - - #[test] - #[should_panic(expected = "attempt to multiply with overflow")] - fn op_mul_overflow_should_panic() { - let a = FixedU128::max_value(); - let b = 2.into(); - let _c = a * b; - } - - #[test] - fn op_mul_works() { - let a = FixedU128::saturating_from_rational(1, 2); - let b = FixedU128::saturating_from_rational(5, 3); - assert_eq!(FixedU128::saturating_from_rational(5, 6), a * b); - } - - #[test] - fn op_checked_div_with_zero_should_be_none() { - let a = FixedU128::min_value(); - let b = 0.into(); - assert!(a.checked_div(&b).is_none()); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn op_div_zero_should_panic() { - let a = FixedU128::max_value(); - let b = 0.into(); - let _c = a / b; - } - - #[test] - fn op_div_works() { - let a = FixedU128::saturating_from_rational(1, 2); - let b = FixedU128::saturating_from_rational(5, 3); - assert_eq!(FixedU128::saturating_from_rational(3, 10), a / b); - } - - #[test] - fn saturation_from_integer_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - let accuracy = FixedU128::accuracy(); - - // Cases where integer fits. - let a = FixedU128::saturating_from_integer(42); - assert_eq!(a.into_inner(), 42 * accuracy); - - // Cases where pass an negative number, should return zero - let a = FixedU128::saturating_from_integer(-42); - assert_eq!(a.into_inner(), 0); - - // Max/min integers that fit. - let a = FixedU128::saturating_from_integer(inner_max / accuracy); - assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy); - - let a = FixedU128::saturating_from_integer(inner_min / accuracy); - assert_eq!(a.into_inner(), (inner_min / accuracy) * accuracy); - - // Cases where integer doesn't fit, so it saturates. - let a = FixedU128::saturating_from_integer(inner_max / accuracy + 1); - assert_eq!(a.into_inner(), inner_max); - } - - #[test] - fn checked_from_integer_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - let accuracy = FixedU128::accuracy(); - - // Cases where integer fits. - let a = FixedU128::checked_from_integer(42).expect("42 * accuracy < inner_max, qed"); - assert_eq!(a.into_inner(), 42 * accuracy); - - // Max/min integers that fit. - let a = FixedU128::checked_from_integer(inner_max / accuracy).expect("inner_max / accuracy < inner_max, qed"); - assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy); - - let a = FixedU128::checked_from_integer(inner_min).expect("inner_min = 0, qed"); - assert_eq!(a.into_inner(), inner_min); - - // Cases where integer not fit. - let a = FixedU128::checked_from_integer(inner_max / accuracy + 1); - assert_eq!(a, None); - } - - #[test] - fn from_inner_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - assert_eq!(FixedU128::max_value(), FixedU128::from_inner(inner_max)); - assert_eq!(FixedU128::min_value(), FixedU128::from_inner(inner_min)); - } - - #[test] - fn saturating_from_ration_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - let accuracy = FixedU128::accuracy(); - - // Cases where parameters fit. - let a = FixedU128::saturating_from_rational(3, 5); - assert_eq!(a.into_inner(), 3 * accuracy / 5); - - // Cases where MIX/MIN - let a = FixedU128::saturating_from_rational(inner_min, 1); - assert_eq!(a.into_inner(), inner_min); - - let a = FixedU128::saturating_from_rational(inner_max, 1); - assert_eq!(a.into_inner(), inner_max); - - // Cases where parameters are negative should return zero - let a = FixedU128::saturating_from_rational(-1, 1); - assert_eq!(a.into_inner(), 0); - - let a = FixedU128::saturating_from_rational(1, -1); - assert_eq!(a.into_inner(), 0); - - let a = FixedU128::saturating_from_rational(-3, -5); - assert_eq!(a.into_inner(), 0); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn saturation_from_ration_with_zero_should_panic() { - let _a = FixedU128::saturating_from_rational(100, 0); - } - - #[test] - fn checked_from_rational_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - let accuracy = FixedU128::accuracy(); - - let a = FixedU128::checked_from_rational(3, 5).expect("3 * accuracy / 5 < inner_max, qed"); - assert_eq!(a.into_inner(), 3 * accuracy / 5); - - // Case: limit - let a = FixedU128::checked_from_rational(inner_min, 1).expect("inner_min / 1 = inner_min, qed"); - assert_eq!(a.into_inner(), inner_min); - - let a = FixedU128::saturating_from_rational(inner_max, 1); - assert_eq!(a.into_inner(), inner_max); - - let a = FixedU128::checked_from_rational(inner_max / accuracy, 1) - .expect("inner_max / accuracy * accuracy < inner_max, qed"); - assert_eq!(a.into_inner(), inner_max / accuracy * accuracy); - - let a = FixedU128::checked_from_rational(inner_min as i128 - 1, 1); - assert_eq!(a, None); - - let a = FixedU128::checked_from_rational(inner_max, 1); - assert_eq!(a, None); - - // Cases where parameters are negative should return None - let a = FixedU128::checked_from_rational(3, -5); - assert_eq!(a, None); - - let a = FixedU128::checked_from_rational(-3, 5); - assert_eq!(a, None); - - let a = FixedU128::checked_from_rational(-3, -5); - assert_eq!(a, None); - - // Case: divided zero should return None - let a = FixedU128::checked_from_rational(10, 0); - assert_eq!(a, None); - } - - #[test] - fn checked_mul_int_works() { - let a = FixedU128::saturating_from_rational(10, 1); - let b = u32::max_value() / 5; - assert_eq!(a.checked_mul_int(b), None); - - let a = FixedU128::saturating_from_integer(120); - let b = 2i32; - assert_eq!(a.checked_mul_int::<i32>(b), Some(240)); - - let a = FixedU128::saturating_from_rational(1, 2); - let b = 20i32; - assert_eq!(a.checked_mul_int::<i32>(b), Some(10)); - - // Case where the integer is negative should return None - let a = FixedU128::saturating_from_rational(1, 2); - let b = -20i32; - assert_eq!(a.checked_mul_int::<i32>(b), None); - } - - #[test] - fn saturating_mul_int_works() { - let a = FixedU128::saturating_from_integer(2); - // Max - 1. - assert_eq!(a.saturating_mul_int((i128::max_value() - 1) / 2), i128::max_value() - 1); - // Max - assert_eq!(a.saturating_mul_int(i128::max_value() / 2), i128::max_value() - 1); - // Max + 1 => saturates to max. - assert_eq!(a.saturating_mul_int(i128::max_value() / 2 + 1), i128::max_value()); - - let a = FixedU128::saturating_from_rational(1, 2); - assert_eq!(a.saturating_mul_int(42i32), 21); - assert_eq!(a.saturating_mul_int(i128::max_value()), i128::max_value() / 2); - - // Case: saturating max - let c = FixedU128::saturating_from_integer(255); - assert_eq!(c.saturating_mul_int(2i8), i8::max_value()); - assert_eq!(c.saturating_mul_int(i128::max_value()), i128::max_value()); - - // Case: negative => 0 - assert_eq!(a.saturating_mul_int(-2i8), 0i8); - assert_eq!(a.saturating_mul_int(i128::min_value()), 0i128); - } - - #[test] - fn checked_div_int_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - let accuracy = FixedU128::accuracy(); - - let a = FixedU128::from_inner(inner_max); - let b = FixedU128::from_inner(inner_min); - let c = FixedU128::zero(); - let d = FixedU128::one(); - let e = FixedU128::saturating_from_integer(6); - let f = FixedU128::saturating_from_integer(5); - - assert_eq!(e.checked_div_int(2.into()), Some(3)); - assert_eq!(f.checked_div_int(2.into()), Some(2)); - - assert_eq!(a.checked_div_int(i128::max_value()), Some(0)); - assert_eq!(a.checked_div_int(2), Some(inner_max / (2 * accuracy))); - assert_eq!(a.checked_div_int(inner_max / accuracy), Some(1)); - assert_eq!(a.checked_div_int(1i8), None); - - assert_eq!(b.checked_div_int(2), Some(0)); - assert_eq!(b.checked_div_int(1i8), Some(0)); - - assert_eq!(c.checked_div_int(1), Some(0)); - assert_eq!(c.checked_div_int(i128::max_value()), Some(0)); - assert_eq!(c.checked_div_int(1i8), Some(0)); - - assert_eq!(d.checked_div_int(1), Some(1)); - assert_eq!(d.checked_div_int(i32::max_value()), Some(0)); - - assert_eq!(d.checked_div_int(1i8), Some(1)); - - assert_eq!(a.checked_div_int(0), None); - assert_eq!(b.checked_div_int(0), None); - assert_eq!(c.checked_div_int(0), None); - assert_eq!(d.checked_div_int(0), None); - } - - #[test] - fn saturating_div_int_works() { - let a = FixedU128::max_value(); - let b = 5u32; - assert_eq!(a.saturating_div_int(b), u32::max_value()); - - let a = FixedU128::saturating_from_integer(100); - let b = 10u8; - assert_eq!(a.saturating_div_int(b), 10u8); - - // Case where the integer is negative should return zero - let a = FixedU128::saturating_from_integer(100); - let b = -10; - assert_eq!(a.saturating_div_int(b), 0); - - let a = FixedU128::saturating_from_integer(100); - let b = 10; - assert_eq!(a.saturating_div_int(b), 10); - } - - #[test] - fn saturating_mul_acc_int_works() { - assert_eq!(FixedU128::zero().saturating_mul_acc_int(42u8), 42u8); - assert_eq!(FixedU128::one().saturating_mul_acc_int(42u8), 2 * 42u8); - - assert_eq!( - FixedU128::one().saturating_mul_acc_int(i128::max_value()), - i128::max_value() - ); - assert_eq!( - FixedU128::one().saturating_mul_acc_int(i128::min_value()), - i128::min_value() - ); - - assert_eq!( - FixedU128::one().saturating_mul_acc_int(u128::max_value() / 2), - u128::max_value() - 1 - ); - } - - #[test] - fn checked_div_works() { - let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value(); - let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value(); - - let a = FixedU128::from_inner(inner_max); - let b = FixedU128::from_inner(inner_min); - let c = FixedU128::zero(); - let d = FixedU128::one(); - let e = FixedU128::saturating_from_integer(6); - let f = FixedU128::saturating_from_integer(5); - - assert_eq!(e.checked_div(&2.into()), Some(3.into())); - assert_eq!( - f.checked_div(&2.into()), - Some(FixedU128::saturating_from_rational(10, 4)) - ); - - assert_eq!(a.checked_div(&inner_max.into()), Some(1.into())); - assert_eq!(a.checked_div(&2.into()), Some(FixedU128::from_inner(inner_max / 2))); - assert_eq!(a.checked_div(&FixedU128::max_value()), Some(1.into())); - assert_eq!(a.checked_div(&d), Some(a)); - - // Cases inner_min is zero - assert_eq!(b.checked_div(&b), None); - - assert_eq!(c.checked_div(&1.into()), Some(0.into())); - assert_eq!(c.checked_div(&FixedU128::max_value()), Some(0.into())); - - assert_eq!(d.checked_div(&1.into()), Some(1.into())); - - assert_eq!(a.checked_div(&FixedU128::one()), Some(a)); - assert_eq!(b.checked_div(&FixedU128::one()), Some(b)); - assert_eq!(c.checked_div(&FixedU128::one()), Some(c)); - assert_eq!(d.checked_div(&FixedU128::one()), Some(d)); - - assert_eq!(a.checked_div(&FixedU128::zero()), None); - assert_eq!(b.checked_div(&FixedU128::zero()), None); - assert_eq!(c.checked_div(&FixedU128::zero()), None); - assert_eq!(d.checked_div(&FixedU128::zero()), None); - } - - #[test] - fn trunc_works() { - let n = FixedU128::saturating_from_rational(5, 2).trunc(); - assert_eq!(n, FixedU128::saturating_from_integer(2)); - } - - #[test] - fn frac_works() { - let n = FixedU128::saturating_from_rational(5, 2); - let i = n.trunc(); - let f = n.frac(); - - assert_eq!(n, i + f); - - let n = FixedU128::saturating_from_rational(5, 2) - .frac() - .saturating_mul(10.into()); - assert_eq!(n, 5.into()); - - let n = FixedU128::saturating_from_rational(1, 2) - .frac() - .saturating_mul(10.into()); - assert_eq!(n, 5.into()); - } - - #[test] - fn ceil_works() { - let n = FixedU128::saturating_from_rational(5, 2); - assert_eq!(n.ceil(), 3.into()); - - // On the limits: - let n = FixedU128::max_value(); - assert_eq!(n.ceil(), n.trunc()); - - let n = FixedU128::min_value(); - assert_eq!(n.ceil(), n.trunc()); - } - - #[test] - fn floor_works() { - let n = FixedU128::saturating_from_rational(5, 2); - assert_eq!(n.floor(), 2.into()); - - // On the limits: - let n = FixedU128::max_value(); - assert_eq!(n.floor(), n.trunc()); - - let n = FixedU128::min_value(); - assert_eq!(n.floor(), n.trunc()); - } - - #[test] - fn round_works() { - let n = FixedU128::zero(); - assert_eq!(n.round(), n); - - let n = FixedU128::one(); - assert_eq!(n.round(), n); - - let n = FixedU128::saturating_from_rational(5, 2); - assert_eq!(n.round(), 3.into()); - - let n = FixedU128::max_value(); - assert_eq!(n.round(), n.trunc()); - - let n = FixedU128::min_value(); - assert_eq!(n.round(), n.trunc()); - - // On the limit: - - // floor(max - 1) + 0.33.. - let n = FixedU128::max_value() - .saturating_sub(1.into()) - .trunc() - .saturating_add(FixedU128::saturating_from_rational(1, 3)); - - assert_eq!(n.round(), (FixedU128::max_value() - 1.into()).trunc()); - - // floor(min + 1) - 0.33.. - let n = FixedU128::min_value() - .saturating_add(1.into()) - .trunc() - .saturating_sub(FixedU128::saturating_from_rational(1, 3)); - - assert_eq!(n.round(), (FixedU128::min_value() + 1.into()).trunc()); - - // floor(max - 1) + 0.6 - let n = FixedU128::max_value() - .saturating_sub(1.into()) - .trunc() - .saturating_add(FixedU128::saturating_from_rational(1, 2)); - - assert_eq!(n.round(), FixedU128::max_value().trunc()); - - // floor(min + 1) - 0.6 - let n = FixedU128::min_value() - .saturating_add(1.into()) - .trunc() - .saturating_sub(FixedU128::saturating_from_rational(10, 6)); - - assert_eq!(n.round(), FixedU128::min_value().trunc()); - } - - #[test] - fn perthing_into_fixed_u128() { - let ten_percent_percent: FixedU128 = Percent::from_percent(10).into(); - assert_eq!(ten_percent_percent.into_inner(), DIV / 10); - - let ten_percent_permill: FixedU128 = Permill::from_percent(10).into(); - assert_eq!(ten_percent_permill.into_inner(), DIV / 10); - - let ten_percent_perbill: FixedU128 = Perbill::from_percent(10).into(); - assert_eq!(ten_percent_perbill.into_inner(), DIV / 10); - - let ten_percent_perquintill: FixedU128 = Perquintill::from_percent(10).into(); - assert_eq!(ten_percent_perquintill.into_inner(), DIV / 10); - } - - #[test] - fn recip_works() { - let a = FixedU128::from_natural(2); - assert_eq!(a.reciprocal(), Some(FixedU128::saturating_from_rational(1, 2))); - - let a = FixedU128::from_natural(2); - assert_eq!(a.reciprocal().unwrap().checked_mul_int(4i32), Some(2i32)); - - let a = FixedU128::saturating_from_rational(100, 121); - assert_eq!(a.reciprocal(), Some(FixedU128::saturating_from_rational(121, 100))); - - let a = FixedU128::saturating_from_rational(1, 2); - assert_eq!( - a.reciprocal().unwrap().checked_mul(&a), - Some(FixedU128::from_natural(1)) - ); - - let a = FixedU128::from_natural(0); - assert_eq!(a.reciprocal(), None); - } - - #[test] - fn serialize_deserialize_works() { - let two_point_five = FixedU128::saturating_from_rational(5, 2); - let serialized = serde_json::to_string(&two_point_five).unwrap(); - assert_eq!(serialized, "\"2500000000000000000\""); - let deserialized: FixedU128 = serde_json::from_str(&serialized).unwrap(); - assert_eq!(deserialized, two_point_five); - } -} diff --git a/utilities/src/lib.rs b/utilities/src/lib.rs index 4e8662c..2741e62 100644 --- a/utilities/src/lib.rs +++ b/utilities/src/lib.rs @@ -1,10 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -pub mod fixed_u128; -pub mod linked_item; pub mod ordered_set; -pub use fixed_u128::FixedU128; -pub use fixed_u128::FixedUnsignedNumber; -pub use linked_item::{LinkedItem, LinkedList}; pub use ordered_set::OrderedSet; diff --git a/utilities/src/linked_item.rs b/utilities/src/linked_item.rs deleted file mode 100644 index 5be0eba..0000000 --- a/utilities/src/linked_item.rs +++ /dev/null @@ -1,429 +0,0 @@ -use codec::{Decode, Encode}; -use frame_support::{Parameter, StorageMap}; -use sp_runtime::{traits::Member, RuntimeDebug}; -use sp_std::{iter, marker, prelude::*}; - -#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode)] -pub struct LinkedItem<Item> { - pub prev: Option<Item>, - pub next: Option<Item>, -} - -impl<Item> Default for LinkedItem<Item> { - fn default() -> Self { - LinkedItem { prev: None, next: None } - } -} - -pub struct LinkedList<Storage, Key, Item>(marker::PhantomData<(Storage, Key, Item)>); - -impl<Storage, Key, Value> LinkedList<Storage, Key, Value> -where - Value: Parameter + Member + Copy, - Key: Parameter, - Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, -{ - fn read_head(key: &Key) -> LinkedItem<Value> { - Self::read(key, None) - } - - fn write_head(key: &Key, item: LinkedItem<Value>) { - Self::write(key, None, item); - } - - fn read(key: &Key, value: Option<Value>) -> LinkedItem<Value> { - Storage::get(&(key.clone(), value)).unwrap_or_else(Default::default) - } - - fn take(key: &Key, value: Value) -> LinkedItem<Value> { - let item = Self::read(key, Some(value)); - Self::remove(key, value); - item - } - - fn write(key: &Key, value: Option<Value>, item: LinkedItem<Value>) { - Storage::insert(&(key.clone(), value), item); - } - - pub fn append(key: &Key, value: Value) { - let head = Self::read_head(key); - let new_head = LinkedItem { - prev: Some(value), - next: head.next, - }; - - Self::write_head(key, new_head); - - let prev = Self::read(key, head.prev); - let new_prev = LinkedItem { - prev: prev.prev, - next: Some(value), - }; - Self::write(key, head.prev, new_prev); - - let item = LinkedItem { - prev: head.prev, - next: None, - }; - Self::write(key, Some(value), item); - } - - pub fn remove(key: &Key, value: Value) { - if let Some(item) = Storage::take(&(key.clone(), Some(value))) { - let prev = Self::read(key, item.prev); - let new_prev = LinkedItem { - prev: prev.prev, - next: item.next, - }; - - Self::write(key, item.prev, new_prev); - - let next = Self::read(key, item.next); - let new_next = LinkedItem { - prev: item.prev, - next: next.next, - }; - - Self::write(key, item.next, new_next); - } - } - - pub fn enumerate(key: &Key) -> Enumerator<Key, Value, Self> { - Enumerator::<Key, Value, Self>::new(key, false, Self::read_head(key)) - } - - pub fn take_all(key: &Key) -> Enumerator<Key, Value, Self> { - Enumerator::<Key, Value, Self>::new(key, true, Self::read_head(key)) - } -} - -pub struct Enumerator<Key, Value, LinkedList> { - key: Key, - should_take: bool, - linkage: LinkedItem<Value>, - next_fn: fn(&mut Enumerator<Key, Value, LinkedList>) -> Option<Value>, - _phantom: marker::PhantomData<LinkedList>, -} - -impl<Key, Value, Storage> Enumerator<Key, Value, LinkedList<Storage, Key, Value>> -where - Key: Parameter, - Value: Parameter + Member + Copy, - Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, -{ - fn new(key: &Key, should_take: bool, linkage: LinkedItem<Value>) -> Self { - Self { - key: key.clone(), - should_take, - linkage, - next_fn: Self::next, - _phantom: Default::default(), - } - } - fn next(&mut self) -> Option<Value> { - let next_value = self.linkage.next?; - if self.should_take { - self.linkage = <LinkedList<Storage, Key, Value>>::take(&self.key, next_value); - } else { - self.linkage = <LinkedList<Storage, Key, Value>>::read(&self.key, Some(next_value)); - } - Some(next_value) - } -} - -impl<Key, Value, Storage> iter::Iterator for Enumerator<Key, Value, LinkedList<Storage, Key, Value>> -where - Key: Parameter, - Value: Parameter + Member + Copy, - Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, -{ - type Item = Value; - - fn next(&mut self) -> Option<Self::Item> { - let next_fn = self.next_fn; - next_fn(self) - } -} - -impl<Key, Value, LinkedList> Drop for Enumerator<Key, Value, LinkedList> { - fn drop(&mut self) { - if !self.should_take { - return; - } - - let next_fn = self.next_fn; - while next_fn(self).is_some() {} - } -} - -#[cfg(test)] -mod tests { - use super::*; - use frame_support::{decl_module, decl_storage, impl_outer_origin, parameter_types}; - use frame_system as system; - use sp_core::H256; - use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; - - type Key = u64; - type Value = u32; - pub trait Trait: frame_system::Trait {} - - type TestLinkedItem = LinkedItem<Value>; - - decl_storage! { - trait Store for Module<T: Trait> as Test { - pub TestItem get(fn linked_list): map hasher(blake2_128_concat) (Key, Option<Value>) => Option<TestLinkedItem>; - } - } - - decl_module! { - pub struct Module<T: Trait> for enum Call where origin: T::Origin { - } - } - - impl_outer_origin! { - pub enum Origin for Test {} - } - - // For testing the module, we construct most of a mock runtime. This means - // first constructing a configuration type (`Test`) which `impl`s each of the - // configuration traits of modules we want to use. - #[derive(Clone, Eq, PartialEq, Debug)] - pub struct Test; - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - impl frame_system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = (); - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = u128; - type Lookup = IdentityLookup<Self::AccountId>; - type Header = Header; - type Event = (); - type BlockHashCount = BlockHashCount; - type MaximumBlockWeight = MaximumBlockWeight; - type MaximumBlockLength = MaximumBlockLength; - type AvailableBlockRatio = AvailableBlockRatio; - type Version = (); - type ModuleToIndex = (); - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BlockExecutionWeight = (); - type ExtrinsicBaseWeight = (); - type MaximumExtrinsicWeight = (); - } - - type TestLinkedList = LinkedList<TestItem, Key, Value>; - - pub fn new_test_ext() -> sp_io::TestExternalities { - frame_system::GenesisConfig::default() - .build_storage::<Test>() - .unwrap() - .into() - } - - #[test] - fn linked_list_can_append_values() { - new_test_ext().execute_with(|| { - TestLinkedList::append(&0, 1); - - assert_eq!( - TestItem::get(&(0, None)), - Some(TestLinkedItem { - prev: Some(1), - next: Some(1), - }) - ); - - assert_eq!(TestItem::get(&(0, Some(1))), Some(Default::default())); - - TestLinkedList::append(&0, 2); - - assert_eq!( - TestItem::get(&(0, None)), - Some(TestLinkedItem { - prev: Some(2), - next: Some(1), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(1))), - Some(TestLinkedItem { - prev: None, - next: Some(2), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(2))), - Some(TestLinkedItem { - prev: Some(1), - next: None, - }) - ); - - TestLinkedList::append(&0, 3); - - assert_eq!( - TestItem::get(&(0, None)), - Some(TestLinkedItem { - prev: Some(3), - next: Some(1), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(1))), - Some(TestLinkedItem { - prev: None, - next: Some(2), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(2))), - Some(TestLinkedItem { - prev: Some(1), - next: Some(3), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(3))), - Some(TestLinkedItem { - prev: Some(2), - next: None, - }) - ); - }); - } - - #[test] - fn linked_list_can_remove_values() { - new_test_ext().execute_with(|| { - TestLinkedList::append(&0, 1); - TestLinkedList::append(&0, 2); - TestLinkedList::append(&0, 3); - - TestLinkedList::remove(&0, 2); - - assert_eq!( - TestItem::get(&(0, None)), - Some(TestLinkedItem { - prev: Some(3), - next: Some(1), - }) - ); - - assert_eq!( - TestItem::get(&(0, Some(1))), - Some(TestLinkedItem { - prev: None, - next: Some(3), - }) - ); - - assert_eq!(TestItem::get(&(0, Some(2))), None); - - assert_eq!( - TestItem::get(&(0, Some(3))), - Some(TestLinkedItem { - prev: Some(1), - next: None, - }) - ); - - TestLinkedList::remove(&0, 1); - - assert_eq!( - TestItem::get(&(0, None)), - Some(TestLinkedItem { - prev: Some(3), - next: Some(3), - }) - ); - - assert_eq!(TestItem::get(&(0, Some(1))), None); - - assert_eq!(TestItem::get(&(0, Some(2))), None); - - assert_eq!(TestItem::get(&(0, Some(3))), Some(Default::default())); - - TestLinkedList::remove(&0, 3); - - assert_eq!(TestItem::get(&(0, None)), Some(Default::default())); - - assert_eq!(TestItem::get(&(0, Some(1))), None); - - assert_eq!(TestItem::get(&(0, Some(2))), None); - - assert_eq!(TestItem::get(&(0, Some(2))), None); - }); - } - - #[test] - fn linked_list_can_enumerate() { - new_test_ext().execute_with(|| { - let v: Vec<u32> = vec![]; - assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v); - - TestLinkedList::append(&0, 1); - TestLinkedList::append(&0, 2); - TestLinkedList::append(&0, 3); - - // iteration - assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), [1, 2, 3]); - - // should not take - assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), [1, 2, 3]); - }); - } - - #[test] - fn linked_list_can_take_all() { - new_test_ext().execute_with(|| { - let v: Vec<u32> = vec![]; - assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), v); - - TestLinkedList::append(&0, 1); - TestLinkedList::append(&0, 2); - TestLinkedList::append(&0, 3); - - assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), [1, 2, 3]); - - assert_eq!(TestItem::get(&(0, Some(1))), None); - assert_eq!(TestItem::get(&(0, Some(2))), None); - assert_eq!(TestItem::get(&(0, Some(3))), None); - assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v); - }); - } - - #[test] - fn linked_list_take_all_is_safe() { - new_test_ext().execute_with(|| { - let v: Vec<u32> = vec![]; - assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), v); - - TestLinkedList::append(&0, 1); - TestLinkedList::append(&0, 2); - TestLinkedList::append(&0, 3); - - let _ = TestLinkedList::take_all(&0); - - assert_eq!(TestItem::get(&(0, Some(1))), None); - assert_eq!(TestItem::get(&(0, Some(2))), None); - assert_eq!(TestItem::get(&(0, Some(3))), None); - assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v); - }); - } -} diff --git a/vesting/Cargo.toml b/vesting/Cargo.toml index 4363c10..3b9b7b8 100644 --- a/vesting/Cargo.toml +++ b/vesting/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-vesting" description = "Provides scheduled balance locking mechanism, in a *graded vesting* way." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/vesting" license = "Apache-2.0" -version = "0.1.2-dev" +version = "0.1.3-dev" authors = ["Laminar Developers <hello@laminar.one>"] edition = "2018" -- GitLab