mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 11:07:56 +00:00
Remove Copy from Ensure* traits (#13043)
* Remove Copy from EnsureOp and EnsureOpAssign Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove Copy from EnsureFrom and EnsureInto Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix default impl Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Reuse assignment code in Ensure trait Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Require Ensure for all BaseArithmetic types Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix assign impls Co-authored-by: Luis Enrique Muñoz Martín <lemunozm@gmail.com> Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add tests Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add success doc tests Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
This commit is contained in:
committed by
GitHub
parent
841fcaba2c
commit
78621b8dac
@@ -57,6 +57,7 @@ pub trait BaseArithmetic:
|
||||
+ CheckedMul
|
||||
+ CheckedDiv
|
||||
+ CheckedRem
|
||||
+ Ensure
|
||||
+ Saturating
|
||||
+ PartialOrd<Self>
|
||||
+ Ord
|
||||
@@ -113,6 +114,7 @@ impl<
|
||||
+ CheckedMul
|
||||
+ CheckedDiv
|
||||
+ CheckedRem
|
||||
+ Ensure
|
||||
+ Saturating
|
||||
+ PartialOrd<Self>
|
||||
+ Ord
|
||||
@@ -344,13 +346,24 @@ mod ensure {
|
||||
use crate::{ArithmeticError, FixedPointNumber, FixedPointOperand};
|
||||
|
||||
/// Performs addition that returns [`ArithmeticError`] instead of wrapping around on overflow.
|
||||
pub trait EnsureAdd: CheckedAdd + PartialOrd + Zero + Copy {
|
||||
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};
|
||||
///
|
||||
@@ -367,20 +380,32 @@ mod ensure {
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_add(self, v: Self) -> Result<Self, ArithmeticError> {
|
||||
self.checked_add(&v).ok_or_else(|| error::equivalent(v))
|
||||
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: CheckedSub + PartialOrd + Zero + Copy {
|
||||
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};
|
||||
///
|
||||
@@ -397,20 +422,32 @@ mod ensure {
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// ```
|
||||
fn ensure_sub(self, v: Self) -> Result<Self, ArithmeticError> {
|
||||
self.checked_sub(&v).ok_or_else(|| error::inverse(v))
|
||||
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: CheckedMul + PartialOrd + Zero + Copy {
|
||||
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};
|
||||
///
|
||||
@@ -427,19 +464,31 @@ mod ensure {
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_mul(self, v: Self) -> Result<Self, ArithmeticError> {
|
||||
self.checked_mul(&v).ok_or_else(|| error::multiplication(self, v))
|
||||
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: CheckedDiv + PartialOrd + Zero + Copy {
|
||||
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};
|
||||
///
|
||||
@@ -456,15 +505,16 @@ mod ensure {
|
||||
/// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero));
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// ```
|
||||
fn ensure_div(self, v: Self) -> Result<Self, ArithmeticError> {
|
||||
self.checked_div(&v).ok_or_else(|| error::division(self, v))
|
||||
fn ensure_div(mut self, v: Self) -> Result<Self, ArithmeticError> {
|
||||
self.ensure_div_assign(v)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CheckedAdd + PartialOrd + Zero + Copy> EnsureAdd for T {}
|
||||
impl<T: CheckedSub + PartialOrd + Zero + Copy> EnsureSub for T {}
|
||||
impl<T: CheckedMul + PartialOrd + Zero + Copy> EnsureMul for T {}
|
||||
impl<T: CheckedDiv + PartialOrd + Zero + Copy> EnsureDiv for T {}
|
||||
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 {}
|
||||
@@ -472,11 +522,23 @@ mod ensure {
|
||||
|
||||
/// Performs self addition that returns [`ArithmeticError`] instead of wrapping around on
|
||||
/// overflow.
|
||||
pub trait EnsureAddAssign: EnsureAdd {
|
||||
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};
|
||||
///
|
||||
@@ -496,18 +558,30 @@ mod ensure {
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_add_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
|
||||
*self = self.ensure_add(v)?;
|
||||
*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: EnsureSub {
|
||||
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};
|
||||
///
|
||||
@@ -527,18 +601,30 @@ mod ensure {
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// ```
|
||||
fn ensure_sub_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
|
||||
*self = self.ensure_sub(v)?;
|
||||
*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: EnsureMul {
|
||||
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};
|
||||
///
|
||||
@@ -558,18 +644,30 @@ mod ensure {
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_mul_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
|
||||
*self = self.ensure_mul(v)?;
|
||||
*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: EnsureDiv {
|
||||
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};
|
||||
///
|
||||
@@ -589,15 +687,15 @@ mod ensure {
|
||||
/// assert_eq!(overflow(), Err(ArithmeticError::Overflow));
|
||||
/// ```
|
||||
fn ensure_div_assign(&mut self, v: Self) -> Result<(), ArithmeticError> {
|
||||
*self = self.ensure_div(v)?;
|
||||
*self = self.checked_div(&v).ok_or_else(|| error::division(self, &v))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EnsureAdd> EnsureAddAssign for T {}
|
||||
impl<T: EnsureSub> EnsureSubAssign for T {}
|
||||
impl<T: EnsureMul> EnsureMulAssign for T {}
|
||||
impl<T: EnsureDiv> EnsureDivAssign for T {}
|
||||
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:
|
||||
@@ -609,7 +707,6 @@ mod ensure {
|
||||
{
|
||||
}
|
||||
|
||||
/// Meta trait that supports all arithmetic operations
|
||||
pub trait Ensure: EnsureOp + EnsureOpAssign {}
|
||||
impl<T: EnsureOp + EnsureOpAssign> Ensure for T {}
|
||||
|
||||
@@ -643,7 +740,7 @@ mod ensure {
|
||||
d: D,
|
||||
) -> Result<Self, ArithmeticError> {
|
||||
<Self as FixedPointNumber>::checked_from_rational(n, d)
|
||||
.ok_or_else(|| error::division(n, d))
|
||||
.ok_or_else(|| error::division(&n, &d))
|
||||
}
|
||||
|
||||
/// Ensure multiplication for integer type `N`. Equal to `self * n`.
|
||||
@@ -670,7 +767,7 @@ mod ensure {
|
||||
/// 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))
|
||||
self.checked_mul_int(n).ok_or_else(|| error::multiplication(&self, &n))
|
||||
}
|
||||
|
||||
/// Ensure division for integer type `N`. Equal to `self / d`.
|
||||
@@ -697,16 +794,14 @@ mod ensure {
|
||||
/// 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))
|
||||
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 + Copy>:
|
||||
TryFrom<T> + PartialOrd + Zero + Copy
|
||||
{
|
||||
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.
|
||||
@@ -728,14 +823,13 @@ mod ensure {
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_from(other: T) -> Result<Self, ArithmeticError> {
|
||||
Self::try_from(other).map_err(|_| error::equivalent(other))
|
||||
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 + Copy>:
|
||||
TryInto<T> + PartialOrd + Zero + Copy
|
||||
{
|
||||
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
|
||||
@@ -757,12 +851,13 @@ mod ensure {
|
||||
/// assert_eq!(underflow(), Err(ArithmeticError::Underflow));
|
||||
/// ```
|
||||
fn ensure_into(self) -> Result<T, ArithmeticError> {
|
||||
self.try_into().map_err(|_| error::equivalent(self))
|
||||
let err = error::equivalent(&self);
|
||||
self.try_into().map_err(|_| err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryFrom<S> + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureFrom<S> for T {}
|
||||
impl<T: TryInto<S> + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureInto<S> for T {}
|
||||
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};
|
||||
@@ -773,9 +868,9 @@ mod ensure {
|
||||
Positive,
|
||||
}
|
||||
|
||||
impl<T: PartialOrd + Zero> From<T> for Signum {
|
||||
fn from(value: T) -> Self {
|
||||
if value < Zero::zero() {
|
||||
impl<T: PartialOrd + Zero> From<&T> for Signum {
|
||||
fn from(value: &T) -> Self {
|
||||
if value < &Zero::zero() {
|
||||
Signum::Negative
|
||||
} else {
|
||||
Signum::Positive
|
||||
@@ -795,23 +890,23 @@ mod ensure {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn equivalent<R: PartialOrd + Zero + Copy>(r: R) -> ArithmeticError {
|
||||
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 + Copy>(r: R) -> ArithmeticError {
|
||||
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 + Copy, R: PartialOrd + Zero + Copy>(
|
||||
l: L,
|
||||
r: R,
|
||||
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,
|
||||
@@ -819,9 +914,9 @@ mod ensure {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn division<N: PartialOrd + Zero + Copy, D: PartialOrd + Zero + Copy>(
|
||||
n: N,
|
||||
d: D,
|
||||
pub fn division<N: PartialOrd + Zero, D: PartialOrd + Zero>(
|
||||
n: &N,
|
||||
d: &D,
|
||||
) -> ArithmeticError {
|
||||
if d.is_zero() {
|
||||
ArithmeticError::DivisionByZero
|
||||
@@ -831,3 +926,106 @@ mod ensure {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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_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, E, P>(pairs: Vec<(V, V)>, ensured: E, unensured: P)
|
||||
where
|
||||
V: Ensure + core::fmt::Debug + Copy,
|
||||
E: Fn(V, V) -> Result<V, ArithmeticError>,
|
||||
P: Fn(&V, &V) -> 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, E, P>(pairs: Vec<(V, V)>, ensured: E, unensured: P)
|
||||
where
|
||||
V: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy,
|
||||
E: Fn(&mut V, V) -> Result<(), ArithmeticError>,
|
||||
P: Fn(V, V) -> 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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user