Files
pezkuwi-subxt/substrate/primitives/arithmetic/src/traits.rs
T
Squirrel bc2e5e1fe2 sp-std -> core (#3199)
First in a series of PRs that reduces our use of sp-std with a view to
deprecating it.

This is just looking at /substrate and moving some of the references
from `sp-std` to `core`.
These particular changes should be uncontroversial.

Where macros are used `::core` should be used to remove any ambiguity.

part of https://github.com/paritytech/polkadot-sdk/issues/2101
2024-02-06 13:01:29 +00:00

1114 lines
32 KiB
Rust

// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Primitive traits for the runtime arithmetic.
use codec::HasCompact;
use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, Shr, Sub, SubAssign,
};
pub use ensure::{
ensure_pow, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign,
EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp,
EnsureOpAssign, EnsureSub, EnsureSubAssign,
};
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{
checked_pow, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl,
CheckedShr, CheckedSub, One, Signed, Unsigned, Zero,
};
use crate::MultiplyRational;
/// A meta trait for arithmetic type operations, regardless of any limitation on size.
pub trait BaseArithmetic:
From<u8>
+ Zero
+ One
+ IntegerSquareRoot
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ Rem<Self, Output = Self>
+ RemAssign<Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ CheckedShl
+ CheckedShr
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ CheckedRem
+ CheckedNeg
+ Ensure
+ Saturating
+ PartialOrd<Self>
+ Ord
+ Bounded
+ HasCompact
+ Sized
+ Clone
+ TryFrom<u8>
+ TryInto<u8>
+ TryFrom<u16>
+ TryInto<u16>
+ TryFrom<u32>
+ TryInto<u32>
+ TryFrom<u64>
+ TryInto<u64>
+ TryFrom<u128>
+ TryInto<u128>
+ TryFrom<usize>
+ TryInto<usize>
+ UniqueSaturatedFrom<u8>
+ UniqueSaturatedInto<u8>
+ UniqueSaturatedFrom<u16>
+ UniqueSaturatedInto<u16>
+ UniqueSaturatedFrom<u32>
+ UniqueSaturatedInto<u32>
+ UniqueSaturatedFrom<u64>
+ UniqueSaturatedInto<u64>
+ UniqueSaturatedFrom<u128>
+ UniqueSaturatedInto<u128>
{
}
impl<
T: From<u8>
+ Zero
+ One
+ IntegerSquareRoot
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ Rem<Self, Output = Self>
+ RemAssign<Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ CheckedShl
+ CheckedShr
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ CheckedRem
+ CheckedNeg
+ Ensure
+ Saturating
+ PartialOrd<Self>
+ Ord
+ Bounded
+ HasCompact
+ Sized
+ Clone
+ TryFrom<u8>
+ TryInto<u8>
+ TryFrom<u16>
+ TryInto<u16>
+ TryFrom<u32>
+ TryInto<u32>
+ TryFrom<u64>
+ TryInto<u64>
+ TryFrom<u128>
+ TryInto<u128>
+ TryFrom<usize>
+ TryInto<usize>
+ UniqueSaturatedFrom<u8>
+ UniqueSaturatedInto<u8>
+ UniqueSaturatedFrom<u16>
+ UniqueSaturatedInto<u16>
+ UniqueSaturatedFrom<u32>
+ UniqueSaturatedInto<u32>
+ UniqueSaturatedFrom<u64>
+ UniqueSaturatedInto<u64>
+ UniqueSaturatedFrom<u128>
+ UniqueSaturatedInto<u128>,
> BaseArithmetic for T
{
}
/// A meta trait for arithmetic.
///
/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to
/// be able to represent at least `u8` values without loss, hence the trait implies `From<u8>`
/// and smaller integers. All other conversions are fallible.
pub trait AtLeast8Bit: BaseArithmetic + From<u8> {}
impl<T: BaseArithmetic + From<u8>> AtLeast8Bit for T {}
/// A meta trait for arithmetic. Same as [`AtLeast8Bit `], but also bounded to be unsigned.
pub trait AtLeast8BitUnsigned: AtLeast8Bit + Unsigned {}
impl<T: AtLeast8Bit + Unsigned> AtLeast8BitUnsigned for T {}
/// A meta trait for arithmetic.
///
/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to
/// be able to represent at least `u16` values without loss, hence the trait implies `From<u16>`
/// and smaller integers. All other conversions are fallible.
pub trait AtLeast16Bit: BaseArithmetic + From<u16> {}
impl<T: BaseArithmetic + From<u16>> AtLeast16Bit for T {}
/// A meta trait for arithmetic. Same as [`AtLeast16Bit `], but also bounded to be unsigned.
pub trait AtLeast16BitUnsigned: AtLeast16Bit + Unsigned {}
impl<T: AtLeast16Bit + Unsigned> AtLeast16BitUnsigned for T {}
/// A meta trait for arithmetic.
///
/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to
/// be able to represent at least `u32` values without loss, hence the trait implies `From<u32>`
/// and smaller integers. All other conversions are fallible.
pub trait AtLeast32Bit: BaseArithmetic + From<u16> + From<u32> {}
impl<T: BaseArithmetic + From<u16> + From<u32>> AtLeast32Bit for T {}
/// A meta trait for arithmetic. Same as [`AtLeast32Bit `], but also bounded to be unsigned.
pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned + MultiplyRational {}
impl<T: AtLeast32Bit + Unsigned + MultiplyRational> AtLeast32BitUnsigned for T {}
/// Just like `From` except that if the source value is too big to fit into the destination type
/// then it'll saturate the destination.
pub trait UniqueSaturatedFrom<T: Sized>: Sized {
/// Convert from a value of `T` into an equivalent instance of `Self`.
fn unique_saturated_from(t: T) -> Self;
}
/// Just like `Into` except that if the source value is too big to fit into the destination type
/// then it'll saturate the destination.
pub trait UniqueSaturatedInto<T: Sized>: Sized {
/// Consume self to return an equivalent value of `T`.
fn unique_saturated_into(self) -> T;
}
impl<T: Sized, S: TryFrom<T> + Bounded + Sized> UniqueSaturatedFrom<T> for S {
fn unique_saturated_from(t: T) -> Self {
S::try_from(t).unwrap_or_else(|_| Bounded::max_value())
}
}
impl<T: Bounded + Sized, S: TryInto<T> + Sized> UniqueSaturatedInto<T> for S {
fn unique_saturated_into(self) -> T {
self.try_into().unwrap_or_else(|_| Bounded::max_value())
}
}
/// Saturating arithmetic operations, returning maximum or minimum values instead of overflowing.
pub trait Saturating {
/// Saturating addition. Compute `self + rhs`, saturating at the numeric bounds instead of
/// overflowing.
fn saturating_add(self, rhs: Self) -> Self;
/// Saturating subtraction. Compute `self - rhs`, saturating at the numeric bounds instead of
/// overflowing.
fn saturating_sub(self, rhs: Self) -> Self;
/// Saturating multiply. Compute `self * rhs`, saturating at the numeric bounds instead of
/// overflowing.
fn saturating_mul(self, rhs: Self) -> Self;
/// Saturating exponentiation. Compute `self.pow(exp)`, saturating at the numeric bounds
/// instead of overflowing.
fn saturating_pow(self, exp: usize) -> Self;
/// Decrement self by one, saturating at zero.
fn saturating_less_one(mut self) -> Self
where
Self: One,
{
self.saturating_dec();
self
}
/// Increment self by one, saturating at the numeric bounds instead of overflowing.
fn saturating_plus_one(mut self) -> Self
where
Self: One,
{
self.saturating_inc();
self
}
/// Increment self by one, saturating.
fn saturating_inc(&mut self)
where
Self: One,
{
let mut o = Self::one();
core::mem::swap(&mut o, self);
*self = o.saturating_add(One::one());
}
/// Decrement self by one, saturating at zero.
fn saturating_dec(&mut self)
where
Self: One,
{
let mut o = Self::one();
core::mem::swap(&mut o, self);
*self = o.saturating_sub(One::one());
}
/// Increment self by some `amount`, saturating.
fn saturating_accrue(&mut self, amount: Self)
where
Self: One,
{
let mut o = Self::one();
core::mem::swap(&mut o, self);
*self = o.saturating_add(amount);
}
/// Decrement self by some `amount`, saturating at zero.
fn saturating_reduce(&mut self, amount: Self)
where
Self: One,
{
let mut o = Self::one();
core::mem::swap(&mut o, self);
*self = o.saturating_sub(amount);
}
}
impl<T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating> Saturating
for T
{
fn saturating_add(self, o: Self) -> Self {
<Self as num_traits::Saturating>::saturating_add(self, o)
}
fn saturating_sub(self, o: Self) -> Self {
<Self as num_traits::Saturating>::saturating_sub(self, o)
}
fn saturating_mul(self, o: Self) -> Self {
self.checked_mul(&o).unwrap_or_else(|| {
if (self < T::zero()) != (o < T::zero()) {
Bounded::min_value()
} else {
Bounded::max_value()
}
})
}
fn saturating_pow(self, exp: usize) -> Self {
let neg = self < T::zero() && exp % 2 != 0;
checked_pow(self, exp).unwrap_or_else(|| {
if neg {
Bounded::min_value()
} else {
Bounded::max_value()
}
})
}
}
/// Convenience type to work around the highly unergonomic syntax needed
/// to invoke the functions of overloaded generic traits, in this case
/// `SaturatedFrom` and `SaturatedInto`.
pub trait SaturatedConversion {
/// Convert from a value of `T` into an equivalent instance of `Self`.
///
/// This just uses `UniqueSaturatedFrom` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_from<T>(t: T) -> Self
where
Self: UniqueSaturatedFrom<T>,
{
<Self as UniqueSaturatedFrom<T>>::unique_saturated_from(t)
}
/// Consume self to return an equivalent value of `T`.
///
/// This just uses `UniqueSaturatedInto` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_into<T>(self) -> T
where
Self: UniqueSaturatedInto<T>,
{
<Self as UniqueSaturatedInto<T>>::unique_saturated_into(self)
}
}
impl<T: Sized> SaturatedConversion for T {}
/// Arithmetic operations with safe error handling.
///
/// This module provide a readable way to do safe arithmetics, turning this:
///
/// ```
/// # use sp_arithmetic::{traits::EnsureSub, ArithmeticError};
/// # fn foo() -> Result<(), ArithmeticError> {
/// # let mut my_value: i32 = 1;
/// # let other_value: i32 = 1;
/// my_value = my_value.checked_sub(other_value).ok_or(ArithmeticError::Overflow)?;
/// # Ok(())
/// # }
/// ```
///
/// into this:
///
/// ```
/// # use sp_arithmetic::{traits::EnsureSubAssign, ArithmeticError};
/// # fn foo() -> Result<(), ArithmeticError> {
/// # let mut my_value: i32 = 1;
/// # let other_value: i32 = 1;
/// my_value.ensure_sub_assign(other_value)?;
/// # Ok(())
/// # }
/// ```
///
/// choosing the correct [`ArithmeticError`](crate::ArithmeticError) it should return in case of
/// fail.
///
/// The *EnsureOps* family functions follows the same behavior as *CheckedOps* but
/// returning an [`ArithmeticError`](crate::ArithmeticError) instead of `None`.
mod ensure {
use super::{checked_pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero};
use crate::{ArithmeticError, FixedPointNumber, FixedPointOperand};
/// Performs addition that returns [`ArithmeticError`] instead of wrapping around on overflow.
pub trait EnsureAdd: EnsureAddAssign {
/// Adds two numbers, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// Similar to [`CheckedAdd::checked_add()`] but returning an [`ArithmeticError`] error.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureAdd;
///
/// let a: i32 = 10;
/// let b: i32 = 20;
///
/// assert_eq!(a.ensure_add(b), Ok(30));
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureAdd, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// u32::MAX.ensure_add(1)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// i32::MIN.ensure_add(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_add(mut self, v: Self) -> Result<Self, ArithmeticError> {
self.ensure_add_assign(v)?;
Ok(self)
}
}
/// Performs subtraction that returns [`ArithmeticError`] instead of wrapping around on
/// underflow.
pub trait EnsureSub: EnsureSubAssign {
/// Subtracts two numbers, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// Similar to [`CheckedSub::checked_sub()`] but returning an [`ArithmeticError`] error.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureSub;
///
/// let a: i32 = 10;
/// let b: i32 = 20;
///
/// assert_eq!(a.ensure_sub(b), Ok(-10));
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureSub, ArithmeticError};
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// 0u32.ensure_sub(1)?;
/// Ok(())
/// }
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// i32::MAX.ensure_sub(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
fn ensure_sub(mut self, v: Self) -> Result<Self, ArithmeticError> {
self.ensure_sub_assign(v)?;
Ok(self)
}
}
/// Performs multiplication that returns [`ArithmeticError`] instead of wrapping around on
/// overflow.
pub trait EnsureMul: EnsureMulAssign {
/// Multiplies two numbers, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// Similar to [`CheckedMul::checked_mul()`] but returning an [`ArithmeticError`] error.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureMul;
///
/// let a: i32 = 10;
/// let b: i32 = 20;
///
/// assert_eq!(a.ensure_mul(b), Ok(200));
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureMul, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// u32::MAX.ensure_mul(2)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// i32::MAX.ensure_mul(-2)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_mul(mut self, v: Self) -> Result<Self, ArithmeticError> {
self.ensure_mul_assign(v)?;
Ok(self)
}
}
/// Performs division that returns [`ArithmeticError`] instead of wrapping around on overflow.
pub trait EnsureDiv: EnsureDivAssign {
/// Divides two numbers, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// Similar to [`CheckedDiv::checked_div()`] but returning an [`ArithmeticError`] error.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureDiv;
///
/// let a: i32 = 20;
/// let b: i32 = 10;
///
/// assert_eq!(a.ensure_div(b), Ok(2));
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureDiv, ArithmeticError};
///
/// fn extrinsic_zero() -> Result<(), ArithmeticError> {
/// 1.ensure_div(0)?;
/// Ok(())
/// }
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// i64::MIN.ensure_div(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero));
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
fn ensure_div(mut self, v: Self) -> Result<Self, ArithmeticError> {
self.ensure_div_assign(v)?;
Ok(self)
}
}
/// Raises a value to the power of exp, returning `ArithmeticError` if an overflow occurred.
///
/// Check [`checked_pow`] for more info about border cases.
///
/// ```
/// use sp_arithmetic::{traits::ensure_pow, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// ensure_pow(2u64, 64)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
pub fn ensure_pow<T: One + CheckedMul + Clone>(
base: T,
exp: usize,
) -> Result<T, ArithmeticError> {
checked_pow(base, exp).ok_or(ArithmeticError::Overflow)
}
impl<T: EnsureAddAssign> EnsureAdd for T {}
impl<T: EnsureSubAssign> EnsureSub for T {}
impl<T: EnsureMulAssign> EnsureMul for T {}
impl<T: EnsureDivAssign> EnsureDiv for T {}
/// Meta trait that supports all immutable arithmetic `Ensure*` operations
pub trait EnsureOp: EnsureAdd + EnsureSub + EnsureMul + EnsureDiv {}
impl<T: EnsureAdd + EnsureSub + EnsureMul + EnsureDiv> EnsureOp for T {}
/// Performs self addition that returns [`ArithmeticError`] instead of wrapping around on
/// overflow.
pub trait EnsureAddAssign: CheckedAdd + PartialOrd + Zero {
/// Adds two numbers overwriting the left hand one, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureAddAssign;
///
/// let mut a: i32 = 10;
/// let b: i32 = 20;
///
/// a.ensure_add_assign(b).unwrap();
/// assert_eq!(a, 30);
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureAddAssign, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let mut max = u32::MAX;
/// max.ensure_add_assign(1)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// let mut max = i32::MIN;
/// max.ensure_add_assign(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_add_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
*self = self.checked_add(&v).ok_or_else(|| error::equivalent(&v))?;
Ok(())
}
}
/// Performs self subtraction that returns [`ArithmeticError`] instead of wrapping around on
/// underflow.
pub trait EnsureSubAssign: CheckedSub + PartialOrd + Zero {
/// Subtracts two numbers overwriting the left hand one, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureSubAssign;
///
/// let mut a: i32 = 10;
/// let b: i32 = 20;
///
/// a.ensure_sub_assign(b).unwrap();
/// assert_eq!(a, -10);
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureSubAssign, ArithmeticError};
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// let mut zero: u32 = 0;
/// zero.ensure_sub_assign(1)?;
/// Ok(())
/// }
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let mut zero = i32::MAX;
/// zero.ensure_sub_assign(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
fn ensure_sub_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
*self = self.checked_sub(&v).ok_or_else(|| error::inverse(&v))?;
Ok(())
}
}
/// Performs self multiplication that returns [`ArithmeticError`] instead of wrapping around on
/// overflow.
pub trait EnsureMulAssign: CheckedMul + PartialOrd + Zero {
/// Multiplies two numbers overwriting the left hand one, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureMulAssign;
///
/// let mut a: i32 = 10;
/// let b: i32 = 20;
///
/// a.ensure_mul_assign(b).unwrap();
/// assert_eq!(a, 200);
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureMulAssign, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let mut max = u32::MAX;
/// max.ensure_mul_assign(2)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// let mut max = i32::MAX;
/// max.ensure_mul_assign(-2)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_mul_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
*self = self.checked_mul(&v).ok_or_else(|| error::multiplication(self, &v))?;
Ok(())
}
}
/// Performs self division that returns [`ArithmeticError`] instead of wrapping around on
/// overflow.
pub trait EnsureDivAssign: CheckedDiv + PartialOrd + Zero {
/// Divides two numbers overwriting the left hand one, checking for overflow.
///
/// If it fails, [`ArithmeticError`] is returned.
///
/// # Examples
///
/// ```
/// use sp_arithmetic::traits::EnsureDivAssign;
///
/// let mut a: i32 = 20;
/// let b: i32 = 10;
///
/// a.ensure_div_assign(b).unwrap();
/// assert_eq!(a, 2);
/// ```
///
/// ```
/// use sp_arithmetic::{traits::EnsureDivAssign, ArithmeticError, FixedI64};
///
/// fn extrinsic_zero() -> Result<(), ArithmeticError> {
/// let mut one = 1;
/// one.ensure_div_assign(0)?;
/// Ok(())
/// }
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let mut min = FixedI64::from(i64::MIN);
/// min.ensure_div_assign(FixedI64::from(-1))?;
/// Ok(())
/// }
///
/// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero));
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
fn ensure_div_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
*self = self.checked_div(&v).ok_or_else(|| error::division(self, &v))?;
Ok(())
}
}
impl<T: CheckedAdd + PartialOrd + Zero> EnsureAddAssign for T {}
impl<T: CheckedSub + PartialOrd + Zero> EnsureSubAssign for T {}
impl<T: CheckedMul + PartialOrd + Zero> EnsureMulAssign for T {}
impl<T: CheckedDiv + PartialOrd + Zero> EnsureDivAssign for T {}
/// Meta trait that supports all assigned arithmetic `Ensure*` operations
pub trait EnsureOpAssign:
EnsureAddAssign + EnsureSubAssign + EnsureMulAssign + EnsureDivAssign
{
}
impl<T: EnsureAddAssign + EnsureSubAssign + EnsureMulAssign + EnsureDivAssign> EnsureOpAssign
for T
{
}
pub trait Ensure: EnsureOp + EnsureOpAssign {}
impl<T: EnsureOp + EnsureOpAssign> Ensure for T {}
/// Extends [`FixedPointNumber`] with the Ensure family functions.
pub trait EnsureFixedPointNumber: FixedPointNumber {
/// Creates `self` from a rational number. Equal to `n / d`.
///
/// Returns [`ArithmeticError`] if `d == 0` or `n / d` exceeds accuracy.
///
/// Similar to [`FixedPointNumber::checked_from_rational()`] but returning an
/// [`ArithmeticError`] error.
///
/// ```
/// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64};
///
/// fn extrinsic_zero() -> Result<(), ArithmeticError> {
/// FixedI64::ensure_from_rational(1, 0)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// FixedI64::ensure_from_rational(i64::MAX, -1)?;
/// Ok(())
/// }
///
/// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_from_rational<N: FixedPointOperand, D: FixedPointOperand>(
n: N,
d: D,
) -> Result<Self, ArithmeticError> {
<Self as FixedPointNumber>::checked_from_rational(n, d)
.ok_or_else(|| error::division(&n, &d))
}
/// Ensure multiplication for integer type `N`. Equal to `self * n`.
///
/// Returns [`ArithmeticError`] if the result does not fit in `N`.
///
/// Similar to [`FixedPointNumber::checked_mul_int()`] but returning an [`ArithmeticError`]
/// error.
///
/// ```
/// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// FixedI64::from(i64::MAX).ensure_mul_int(2)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// FixedI64::from(i64::MAX).ensure_mul_int(-2)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_mul_int<N: FixedPointOperand>(self, n: N) -> Result<N, ArithmeticError> {
self.checked_mul_int(n).ok_or_else(|| error::multiplication(&self, &n))
}
/// Ensure division for integer type `N`. Equal to `self / d`.
///
/// Returns [`ArithmeticError`] if the result does not fit in `N` or `d == 0`.
///
/// Similar to [`FixedPointNumber::checked_div_int()`] but returning an [`ArithmeticError`]
/// error.
///
/// ```
/// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64};
///
/// fn extrinsic_zero() -> Result<(), ArithmeticError> {
/// FixedI64::from(1).ensure_div_int(0)?;
/// Ok(())
/// }
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// FixedI64::from(i64::MIN).ensure_div_int(-1)?;
/// Ok(())
/// }
///
/// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero));
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// ```
fn ensure_div_int<D: FixedPointOperand>(self, d: D) -> Result<D, ArithmeticError> {
self.checked_div_int(d).ok_or_else(|| error::division(&self, &d))
}
}
impl<T: FixedPointNumber> EnsureFixedPointNumber for T {}
/// Similar to [`TryFrom`] but returning an [`ArithmeticError`] error.
pub trait EnsureFrom<T: PartialOrd + Zero>: TryFrom<T> + PartialOrd + Zero {
/// Performs the conversion returning an [`ArithmeticError`] if fails.
///
/// Similar to [`TryFrom::try_from()`] but returning an [`ArithmeticError`] error.
///
/// ```
/// use sp_arithmetic::{traits::EnsureFrom, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let byte: u8 = u8::ensure_from(256u16)?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// let byte: i8 = i8::ensure_from(-129i16)?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_from(other: T) -> Result<Self, ArithmeticError> {
let err = error::equivalent(&other);
Self::try_from(other).map_err(|_| err)
}
}
/// Similar to [`TryInto`] but returning an [`ArithmeticError`] error.
pub trait EnsureInto<T: PartialOrd + Zero>: TryInto<T> + PartialOrd + Zero {
/// Performs the conversion returning an [`ArithmeticError`] if fails.
///
/// Similar to [`TryInto::try_into()`] but returning an [`ArithmeticError`] error
///
/// ```
/// use sp_arithmetic::{traits::EnsureInto, ArithmeticError};
///
/// fn overflow() -> Result<(), ArithmeticError> {
/// let byte: u8 = 256u16.ensure_into()?;
/// Ok(())
/// }
///
/// fn underflow() -> Result<(), ArithmeticError> {
/// let byte: i8 = (-129i16).ensure_into()?;
/// Ok(())
/// }
///
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
/// ```
fn ensure_into(self) -> Result<T, ArithmeticError> {
let err = error::equivalent(&self);
self.try_into().map_err(|_| err)
}
}
impl<T: TryFrom<S> + PartialOrd + Zero, S: PartialOrd + Zero> EnsureFrom<S> for T {}
impl<T: TryInto<S> + PartialOrd + Zero, S: PartialOrd + Zero> EnsureInto<S> for T {}
mod error {
use super::{ArithmeticError, Zero};
#[derive(PartialEq)]
enum Signum {
Negative,
Positive,
}
impl<T: PartialOrd + Zero> From<&T> for Signum {
fn from(value: &T) -> Self {
if value < &Zero::zero() {
Signum::Negative
} else {
Signum::Positive
}
}
}
impl core::ops::Mul for Signum {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
if self != rhs {
Signum::Negative
} else {
Signum::Positive
}
}
}
pub fn equivalent<R: PartialOrd + Zero>(r: &R) -> ArithmeticError {
match Signum::from(r) {
Signum::Negative => ArithmeticError::Underflow,
Signum::Positive => ArithmeticError::Overflow,
}
}
pub fn inverse<R: PartialOrd + Zero>(r: &R) -> ArithmeticError {
match Signum::from(r) {
Signum::Negative => ArithmeticError::Overflow,
Signum::Positive => ArithmeticError::Underflow,
}
}
pub fn multiplication<L: PartialOrd + Zero, R: PartialOrd + Zero>(
l: &L,
r: &R,
) -> ArithmeticError {
match Signum::from(l) * Signum::from(r) {
Signum::Negative => ArithmeticError::Underflow,
Signum::Positive => ArithmeticError::Overflow,
}
}
pub fn division<N: PartialOrd + Zero, D: PartialOrd + Zero>(
n: &N,
d: &D,
) -> ArithmeticError {
if d.is_zero() {
ArithmeticError::DivisionByZero
} else {
multiplication(n, d)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ArithmeticError;
use rand::{seq::SliceRandom, thread_rng, Rng};
#[test]
fn ensure_add_works() {
test_ensure(values(), &EnsureAdd::ensure_add, &CheckedAdd::checked_add);
}
#[test]
fn ensure_sub_works() {
test_ensure(values(), &EnsureSub::ensure_sub, &CheckedSub::checked_sub);
}
#[test]
fn ensure_mul_works() {
test_ensure(values(), &EnsureMul::ensure_mul, &CheckedMul::checked_mul);
}
#[test]
fn ensure_div_works() {
test_ensure(values(), &EnsureDiv::ensure_div, &CheckedDiv::checked_div);
}
#[test]
fn ensure_pow_works() {
test_ensure(
values().into_iter().map(|(base, exp)| (base, exp as usize)).collect(),
ensure_pow,
|&a, &b| checked_pow(a, b),
);
}
#[test]
fn ensure_add_assign_works() {
test_ensure_assign(values(), &EnsureAddAssign::ensure_add_assign, &EnsureAdd::ensure_add);
}
#[test]
fn ensure_sub_assign_works() {
test_ensure_assign(values(), &EnsureSubAssign::ensure_sub_assign, &EnsureSub::ensure_sub);
}
#[test]
fn ensure_mul_assign_works() {
test_ensure_assign(values(), &EnsureMulAssign::ensure_mul_assign, &&EnsureMul::ensure_mul);
}
#[test]
fn ensure_div_assign_works() {
test_ensure_assign(values(), &EnsureDivAssign::ensure_div_assign, &EnsureDiv::ensure_div);
}
/// Test that the ensured function returns the expected un-ensured value.
fn test_ensure<V, W, E, P>(pairs: Vec<(V, W)>, ensured: E, unensured: P)
where
V: Ensure + core::fmt::Debug + Copy,
W: Ensure + core::fmt::Debug + Copy,
E: Fn(V, W) -> Result<V, ArithmeticError>,
P: Fn(&V, &W) -> Option<V>,
{
for (a, b) in pairs.into_iter() {
match ensured(a, b) {
Ok(c) => {
assert_eq!(unensured(&a, &b), Some(c))
},
Err(_) => {
assert!(unensured(&a, &b).is_none());
},
}
}
}
/// Test that the ensured function modifies `self` to the expected un-ensured value.
fn test_ensure_assign<V, W, E, P>(pairs: Vec<(V, W)>, ensured: E, unensured: P)
where
V: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy,
W: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy,
E: Fn(&mut V, W) -> Result<(), ArithmeticError>,
P: Fn(V, W) -> Result<V, ArithmeticError> + std::panic::RefUnwindSafe,
{
for (mut a, b) in pairs.into_iter() {
let old_a = a;
match ensured(&mut a, b) {
Ok(()) => {
assert_eq!(unensured(old_a, b), Ok(a));
},
Err(err) => {
assert_eq!(a, old_a, "A stays unmodified in the error case");
assert_eq!(unensured(old_a, b), Err(err));
},
}
}
}
/// Generates some good values for testing integer arithmetic.
fn values() -> Vec<(i32, i32)> {
let mut rng = thread_rng();
let mut one_dimension = || {
let mut ret = vec![0i32; 1007];
// Some hard-coded interesting values.
ret[..7].copy_from_slice(&[-1, 0, 1, i32::MIN, i32::MAX, i32::MAX - 1, i32::MIN + 1]);
// … and some random ones.
rng.fill(&mut ret[7..]);
ret.shuffle(&mut rng);
ret
};
one_dimension().into_iter().zip(one_dimension().into_iter()).collect()
}
}