diff --git a/src/bounds.rs b/src/bounds.rs index acc990ea..42050a79 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,59 @@ 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); +} + +#[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