Introduce DefensiveMin and DefensiveMax (#12554)

* traits for defensive min and defensive max

* defensive min and strict min with tests

* defensive max and strict max with tests

* include docs

* implement partial ord on defensive min and max

* Update frame/support/src/traits/misc.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* wrap lines

* Fix traits

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update frame/support/src/traits/misc.rs

* Update frame/support/src/traits/misc.rs

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: parity-processbot <>
This commit is contained in:
dharjeezy
2022-11-03 20:51:18 +01:00
committed by GitHub
parent 11b6409c12
commit a2e98a943a
2 changed files with 181 additions and 5 deletions
+5 -5
View File
@@ -56,11 +56,11 @@ mod misc;
pub use misc::{
defensive_prelude::{self, *},
Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16,
ConstU32, ConstU64, ConstU8, DefensiveSaturating, DefensiveTruncateFrom,
EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get,
GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker,
OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet,
UnixTime, WrapperKeepOpaque, WrapperOpaque,
ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating,
DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee,
ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType,
Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time,
TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque,
};
#[allow(deprecated)]
pub use misc::{PreimageProvider, PreimageRecipient};
+176
View File
@@ -407,6 +407,134 @@ where
}
}
/// Defensively calculates the minimum of two values.
///
/// Can be used in contexts where we assume the receiver value to be (strictly) smaller.
pub trait DefensiveMin<T> {
/// Returns the minimum and defensively checks that `self` is not larger than `other`.
///
/// # Example
///
/// ```
/// use frame_support::traits::DefensiveMin;
/// // min(3, 4) is 3.
/// assert_eq!(3, 3_u32.defensive_min(4_u32));
/// // min(4, 4) is 4.
/// assert_eq!(4, 4_u32.defensive_min(4_u32));
/// ```
///
/// ```should_panic
/// use frame_support::traits::DefensiveMin;
/// // min(4, 3) panics.
/// 4_u32.defensive_min(3_u32);
/// ```
fn defensive_min(self, other: T) -> Self;
/// Returns the minimum and defensively checks that `self` is smaller than `other`.
///
/// # Example
///
/// ```
/// use frame_support::traits::DefensiveMin;
/// // min(3, 4) is 3.
/// assert_eq!(3, 3_u32.defensive_strict_min(4_u32));
/// ```
///
/// ```should_panic
/// use frame_support::traits::DefensiveMin;
/// // min(4, 4) panics.
/// 4_u32.defensive_strict_min(4_u32);
/// ```
fn defensive_strict_min(self, other: T) -> Self;
}
impl<T> DefensiveMin<T> for T
where
T: sp_std::cmp::PartialOrd<T>,
{
fn defensive_min(self, other: T) -> Self {
if self <= other {
self
} else {
defensive!("DefensiveMin");
other
}
}
fn defensive_strict_min(self, other: T) -> Self {
if self < other {
self
} else {
defensive!("DefensiveMin strict");
other
}
}
}
/// Defensively calculates the maximum of two values.
///
/// Can be used in contexts where we assume the receiver value to be (strictly) larger.
pub trait DefensiveMax<T> {
/// Returns the maximum and defensively asserts that `other` is not larger than `self`.
///
/// # Example
///
/// ```
/// use frame_support::traits::DefensiveMax;
/// // max(4, 3) is 4.
/// assert_eq!(4, 4_u32.defensive_max(3_u32));
/// // max(4, 4) is 4.
/// assert_eq!(4, 4_u32.defensive_max(4_u32));
/// ```
///
/// ```should_panic
/// use frame_support::traits::DefensiveMax;
/// // max(4, 5) panics.
/// 4_u32.defensive_max(5_u32);
/// ```
fn defensive_max(self, other: T) -> Self;
/// Returns the maximum and defensively asserts that `other` is smaller than `self`.
///
/// # Example
///
/// ```
/// use frame_support::traits::DefensiveMax;
/// // y(4, 3) is 4.
/// assert_eq!(4, 4_u32.defensive_strict_max(3_u32));
/// ```
///
/// ```should_panic
/// use frame_support::traits::DefensiveMax;
/// // max(4, 4) panics.
/// 4_u32.defensive_strict_max(4_u32);
/// ```
fn defensive_strict_max(self, other: T) -> Self;
}
impl<T> DefensiveMax<T> for T
where
T: sp_std::cmp::PartialOrd<T>,
{
fn defensive_max(self, other: T) -> Self {
if self >= other {
self
} else {
defensive!("DefensiveMax");
other
}
}
fn defensive_strict_max(self, other: T) -> Self {
if self > other {
self
} else {
defensive!("DefensiveMax strict");
other
}
}
}
/// Anything that can have a `::len()` method.
pub trait Len {
/// Return the length of data type.
@@ -1109,4 +1237,52 @@ mod test {
let data = decoded.encode();
WrapperOpaque::<u32>::decode(&mut &data[..]).unwrap();
}
#[test]
fn defensive_min_works() {
assert_eq!(10, 10_u32.defensive_min(11_u32));
assert_eq!(10, 10_u32.defensive_min(10_u32));
}
#[test]
#[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin\"")]
fn defensive_min_panics() {
10_u32.defensive_min(9_u32);
}
#[test]
fn defensive_strict_min_works() {
assert_eq!(10, 10_u32.defensive_strict_min(11_u32));
assert_eq!(9, 9_u32.defensive_strict_min(10_u32));
}
#[test]
#[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin strict\"")]
fn defensive_strict_min_panics() {
9_u32.defensive_strict_min(9_u32);
}
#[test]
fn defensive_max_works() {
assert_eq!(11, 11_u32.defensive_max(10_u32));
assert_eq!(10, 10_u32.defensive_max(10_u32));
}
#[test]
#[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax\"")]
fn defensive_max_panics() {
9_u32.defensive_max(10_u32);
}
#[test]
fn defensive_strict_max_works() {
assert_eq!(11, 11_u32.defensive_strict_max(10_u32));
assert_eq!(10, 10_u32.defensive_strict_max(9_u32));
}
#[test]
#[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax strict\"")]
fn defensive_strict_max_panics() {
9_u32.defensive_strict_max(9_u32);
}
}