From 79617790ac4fa7c705f75b2c4442521fa222ff82 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Sun, 27 Apr 2025 22:17:59 -0700 Subject: [PATCH 1/2] Add `ConstLowerBounded`/`ConstUpperBounded`/`ConstBounded` traits, impls, and tests --- src/bounds.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/bounds.rs b/src/bounds.rs index acc990ea..7b38719e 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -112,6 +112,80 @@ macro_rules! bounded_tuple { for_each_tuple!(bounded_tuple); bounded_impl!(f64, f64::MIN, f64::MAX); +/// Numbers which have upper and lower bounds +pub trait ConstBounded: ConstLowerBounded + ConstUpperBounded {} + +impl ConstBounded for T {} + +/// Defines an associated constant representing the lower bound of this type +pub trait ConstLowerBounded { + /// The smallest finite number this type can represent + const MIN: Self; +} + +/// Defines an associated constant representing the upper bound of this type +pub trait ConstUpperBounded { + /// The largest finite number this type can represent + const MAX: Self; +} + +macro_rules! const_bounded_impl { + ($t:ty, $min:expr, $max:expr) => { + impl ConstLowerBounded for $t { + const MIN: Self = $min; + } + + impl ConstUpperBounded for $t { + const MAX: Self = $max; + } + }; +} + +const_bounded_impl!(usize, usize::MIN, usize::MAX); +const_bounded_impl!(u8, u8::MIN, u8::MAX); +const_bounded_impl!(u16, u16::MIN, u16::MAX); +const_bounded_impl!(u32, u32::MIN, u32::MAX); +const_bounded_impl!(u64, u64::MIN, u64::MAX); +const_bounded_impl!(u128, u128::MIN, u128::MAX); + +const_bounded_impl!(isize, isize::MIN, isize::MAX); +const_bounded_impl!(i8, i8::MIN, i8::MAX); +const_bounded_impl!(i16, i16::MIN, i16::MAX); +const_bounded_impl!(i32, i32::MIN, i32::MAX); +const_bounded_impl!(i64, i64::MIN, i64::MAX); +const_bounded_impl!(i128, i128::MIN, i128::MAX); + +const_bounded_impl!(f32, f32::MIN, f32::MAX); +const_bounded_impl!(f64, f64::MIN, f64::MAX); + +impl ConstLowerBounded for Wrapping { + const MIN: Self = Wrapping(T::MIN); +} + +impl ConstUpperBounded for Wrapping { + const MAX: Self = Wrapping(T::MAX); +} + +macro_rules! const_lower_bounded_tuple { + ( $($name:ident)* ) => ( + impl<$($name: ConstLowerBounded,)*> ConstLowerBounded for ($($name,)*) { + const MIN: Self = ($($name::MIN,)*); + } + ); +} + +macro_rules! const_upper_bounded_tuple { + ( $($name:ident)* ) => ( + impl<$($name: ConstUpperBounded,)*> ConstUpperBounded for ($($name,)*) { + const MAX: Self = ($($name::MAX,)*); + } + ); +} + +for_each_tuple!(const_lower_bounded_tuple); +for_each_tuple!(const_upper_bounded_tuple); + + #[test] fn wrapping_bounded() { macro_rules! test_wrapping_bounded { @@ -146,3 +220,45 @@ fn wrapping_is_bounded() { require_bounded(&Wrapping(42_u32)); require_bounded(&Wrapping(-42)); } + +#[test] +fn primitives_const_bounded() { + macro_rules! test_primitives_const_bounded { + ($($t:ty)+) => { + $( + assert_eq!(<$t as ConstLowerBounded>::MIN, <$t>::MIN); + assert_eq!(<$t as ConstUpperBounded>::MAX, <$t>::MAX); + )+ + }; + } + + test_primitives_const_bounded!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64); +} + +#[test] +fn wrapping_const_bounded() { + macro_rules! test_wrapping_const_bounded { + ($($t:ty)+) => { + $( + assert_eq!( as ConstLowerBounded>::MIN.0, <$t>::MIN); + assert_eq!( as ConstUpperBounded>::MAX.0, <$t>::MAX); + )+ + }; + } + + test_wrapping_const_bounded!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128); +} + +#[test] +fn func_call_const_bounded() { + fn require_const_bounded(_: &T) -> (T, T) { + (T::MIN, T::MAX) + } + + require_const_bounded(&Wrapping(42_u32)); + require_const_bounded(&Wrapping(-42)); + + require_const_bounded(&27i32); + require_const_bounded(&42usize); + require_const_bounded(&3.1415f32); +} \ No newline at end of file From 8c8e0e463a8792320d01721237b3dcd20837f889 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Sun, 27 Apr 2025 22:26:38 -0700 Subject: [PATCH 2/2] Add `parity_between_bounded_and_const_bounded` test --- src/bounds.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/bounds.rs b/src/bounds.rs index 7b38719e..42050a79 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -261,4 +261,18 @@ fn func_call_const_bounded() { require_const_bounded(&27i32); require_const_bounded(&42usize); require_const_bounded(&3.1415f32); +} + +#[test] +fn parity_between_bounded_and_const_bounded() { + macro_rules! test_parity_between_bounded_and_const_bounded { + ($($t:ty)+) => { + $( + assert_eq!(<$t as ConstLowerBounded>::MIN, <$t as LowerBounded>::min_value()); + assert_eq!(<$t as ConstUpperBounded>::MAX, <$t as UpperBounded>::max_value()); + )+ + }; + } + + test_parity_between_bounded_and_const_bounded!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64); } \ No newline at end of file