From 395b90919ac37148c1550d2bcb4bc4634e72ea4e Mon Sep 17 00:00:00 2001 From: Marc Date: Sun, 31 Mar 2019 22:23:57 +1300 Subject: [PATCH] Add ConstBounded trait Add test const_bounded_impl --- src/bounds.rs | 107 +++++++++++++++++++++++++++++++++++++++++--------- src/lib.rs | 2 + 2 files changed, 91 insertions(+), 18 deletions(-) diff --git a/src/bounds.rs b/src/bounds.rs index a133d7a..adc1eb2 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -7,13 +7,29 @@ use core::{u16, u32, u64, u8, usize}; /// Numbers which have upper and lower bounds pub trait Bounded { - // FIXME (#5527): These should be associated constants /// returns the smallest finite number this type can represent fn min_value() -> Self; /// returns the largest finite number this type can represent fn max_value() -> Self; } +/// Supplimentary trait for [`Bounded`](trait.Bounded.html) types which can be +/// expressed as compile-time constants. +/// +/// This is implemented for all primitive types, and should be implemented +/// wherever possible. Implementors must ensure that `ConstBounded::MIN_VALUE` +/// and `ConstBounded::MAX_VALUE` are the same values produced by +/// [`Bounded::min_value()`](trait.Bounded.html#tymethod.min_value) and +/// [`Bounded::max_value()`](trait.Bounded.html#tymethod.max_value) +/// respectively. +#[cfg(has_associated_consts)] +pub trait ConstBounded: Bounded { + /// The smallest finite number this type can represent + const MIN_VALUE: Self; + /// The largest finite number this type can represent + const MAX_VALUE: Self; +} + macro_rules! bounded_impl { ($t:ty, $min:expr, $max:expr) => { impl Bounded for $t { @@ -30,21 +46,39 @@ macro_rules! bounded_impl { }; } -bounded_impl!(usize, usize::MIN, usize::MAX); -bounded_impl!(u8, u8::MIN, u8::MAX); -bounded_impl!(u16, u16::MIN, u16::MAX); -bounded_impl!(u32, u32::MIN, u32::MAX); -bounded_impl!(u64, u64::MIN, u64::MAX); -#[cfg(has_i128)] -bounded_impl!(u128, u128::MIN, u128::MAX); +#[cfg(has_associated_consts)] +macro_rules! bounded_const_impl { + ($t:ty, $min:expr, $max:expr) => { + bounded_impl!($t, $min, $max); + impl ConstBounded for $t { + const MIN_VALUE: $t = $min; + const MAX_VALUE: $t = $max; + } + } +} +#[cfg(not(has_associated_consts))] +macro_rules! bounded_const_impl { + ($t:ty, $min:expr, $max:expr) => { bounded_impl!($t, $min, $max); }; +} -bounded_impl!(isize, isize::MIN, isize::MAX); -bounded_impl!(i8, i8::MIN, i8::MAX); -bounded_impl!(i16, i16::MIN, i16::MAX); -bounded_impl!(i32, i32::MIN, i32::MAX); -bounded_impl!(i64, i64::MIN, i64::MAX); +bounded_const_impl!(usize, usize::MIN, usize::MAX); +bounded_const_impl!(u8, u8::MIN, u8::MAX); +bounded_const_impl!(u16, u16::MIN, u16::MAX); +bounded_const_impl!(u32, u32::MIN, u32::MAX); +bounded_const_impl!(u64, u64::MIN, u64::MAX); #[cfg(has_i128)] -bounded_impl!(i128, i128::MIN, i128::MAX); +bounded_const_impl!(u128, u128::MIN, u128::MAX); + +bounded_const_impl!(isize, isize::MIN, isize::MAX); +bounded_const_impl!(i8, i8::MIN, i8::MAX); +bounded_const_impl!(i16, i16::MIN, i16::MAX); +bounded_const_impl!(i32, i32::MIN, i32::MAX); +bounded_const_impl!(i64, i64::MIN, i64::MAX); +#[cfg(has_i128)] +bounded_const_impl!(i128, i128::MIN, i128::MAX); + +bounded_const_impl!(f32, f32::MIN, f32::MAX); +bounded_const_impl!(f64, f64::MIN, f64::MAX); impl Bounded for Wrapping { fn min_value() -> Self { @@ -54,8 +88,11 @@ impl Bounded for Wrapping { Wrapping(T::max_value()) } } - -bounded_impl!(f32, f32::MIN, f32::MAX); +#[cfg(has_associated_consts)] +impl ConstBounded for Wrapping { + const MIN_VALUE: Self = Wrapping(T::MIN_VALUE); + const MAX_VALUE: Self = Wrapping(T::MAX_VALUE); +} macro_rules! for_each_tuple_ { ( $m:ident !! ) => ( @@ -86,9 +123,19 @@ macro_rules! bounded_tuple { } ); } - for_each_tuple!(bounded_tuple); -bounded_impl!(f64, f64::MIN, f64::MAX); + +#[cfg(has_associated_consts)] +macro_rules! bounded_const_tuple { + ( $($name:ident)* ) => ( + impl<$($name: ConstBounded,)*> ConstBounded for ($($name,)*) { + const MIN_VALUE: Self = ($($name::MIN_VALUE,)*); + const MAX_VALUE: Self = ($($name::MAX_VALUE,)*); + } + ); +} +#[cfg(has_associated_consts)] +for_each_tuple!(bounded_const_tuple); #[test] fn wrapping_bounded() { @@ -125,3 +172,27 @@ fn wrapping_is_bounded() { require_bounded(&Wrapping(42_u32)); require_bounded(&Wrapping(-42)); } + +#[test] +#[cfg(has_associated_consts)] +fn const_bounded_impl() { + macro_rules! test_traits_match { + ($($t:ty),+) => { $( + assert_eq!( + <$t as Bounded>::min_value(), + <$t as ConstBounded>::MIN_VALUE, + ); + assert_eq!( + <$t as Bounded>::max_value(), + <$t as ConstBounded>::MAX_VALUE, + ); + )+}; + } + test_traits_match!( + u8, u16, u32, u64, usize, + i8, i16, i32, i64, isize, + f32, f64, + Wrapping, Wrapping, + (u8, i32, f32, Wrapping, (i8, ((), u16), Wrapping, f64)) + ); +} diff --git a/src/lib.rs b/src/lib.rs index cb36fcc..85e6f13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,8 @@ use core::ops::{Add, Div, Mul, Rem, Sub}; use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; pub use bounds::Bounded; +#[cfg(has_associated_consts)] +pub use bounds::ConstBounded; #[cfg(feature = "std")] pub use float::Float; pub use float::FloatConst;