Add OneConst and ZeroConst traits

Conditional probing in build script
Force enable with crate feature "associated_consts"
Update README
Add test const_identities
This commit is contained in:
Marc 2018-10-17 15:48:25 +13:00
parent 4ab251b0a2
commit b9c4311fea
5 changed files with 134 additions and 31 deletions

View File

@ -22,3 +22,4 @@ features = ["std"]
default = ["std"]
std = []
i128 = []
associated_consts = []

View File

@ -42,6 +42,10 @@ Implementations for `i128` and `u128` are only available with Rust 1.26 and
later. The build script automatically detects this, but you can make it
mandatory by enabling the `i128` crate feature.
Similarly, additional traits making use of associated constants are available
with Rust 1.22 and later. Again, the build script automatically detects this,
but you can make it mandatory by enabling the `associated_consts` crate feature.
## Releases
Release notes are available in [RELEASES.md](RELEASES.md).

View File

@ -8,6 +8,16 @@ fn main() {
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
panic!("i128 support was not detected!");
}
if probe("fn main() {
struct TestDrop(); impl Drop for TestDrop { fn drop(&mut self) {} }
trait TestConst { const TEST: Self; }
impl TestConst for TestDrop { const TEST: TestDrop = TestDrop(); }
}") {
println!("cargo:rustc-cfg=has_associated_consts");
} else if env::var_os("CARGO_FEATURE_ASSOCIATED_CONSTS").is_some() {
panic!("associated constant support was not detected!");
}
}
/// Test if a code snippet can be compiled

View File

@ -29,6 +29,18 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
fn is_zero(&self) -> bool;
}
/// Supplimentary trait for [`Zero`](trait.Zero.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 `ZeroConst::ZERO` is
/// the same value produced by [`Zero::zero()`](trait.Zero.html#tymethod.zero).
#[cfg(has_associated_consts)]
pub trait ZeroConst: Zero {
/// Additive identity: see [`Zero::zero()`](trait.Zero.html#tymethod.zero).
const ZERO: Self;
}
macro_rules! zero_impl {
($t:ty, $v:expr) => {
impl Zero for $t {
@ -44,24 +56,38 @@ macro_rules! zero_impl {
};
}
zero_impl!(usize, 0);
zero_impl!(u8, 0);
zero_impl!(u16, 0);
zero_impl!(u32, 0);
zero_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(u128, 0);
#[cfg(has_associated_consts)]
macro_rules! zero_const_impl {
($t:ty, $v:expr) => {
zero_impl!($t, $v);
impl ZeroConst for $t {
const ZERO: $t = $v;
}
};
}
#[cfg(not(has_associated_consts))]
macro_rules! zero_const_impl {
($t:ty, $v:expr) => { zero_impl!($t, $v); };
}
zero_impl!(isize, 0);
zero_impl!(i8, 0);
zero_impl!(i16, 0);
zero_impl!(i32, 0);
zero_impl!(i64, 0);
zero_const_impl!(usize, 0);
zero_const_impl!(u8, 0);
zero_const_impl!(u16, 0);
zero_const_impl!(u32, 0);
zero_const_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(i128, 0);
zero_const_impl!(u128, 0);
zero_impl!(f32, 0.0);
zero_impl!(f64, 0.0);
zero_const_impl!(isize, 0);
zero_const_impl!(i8, 0);
zero_const_impl!(i16, 0);
zero_const_impl!(i32, 0);
zero_const_impl!(i64, 0);
#[cfg(has_i128)]
zero_const_impl!(i128, 0);
zero_const_impl!(f32, 0.0);
zero_const_impl!(f64, 0.0);
impl<T: Zero> Zero for Wrapping<T>
where
@ -80,6 +106,14 @@ where
}
}
#[cfg(has_associated_consts)]
impl<T: ZeroConst> ZeroConst for Wrapping<T>
where
Wrapping<T>: Zero,
{
const ZERO: Self = Wrapping(T::ZERO);
}
/// Defines a multiplicative identity element for `Self`.
///
/// # Laws
@ -118,6 +152,18 @@ pub trait One: Sized + Mul<Self, Output = Self> {
}
}
/// Supplimentary trait for [`One`](trait.One.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 `OneConst::ONE` is
/// the same value produced by [`One::one()`](trait.One.html#tymethod.one).
#[cfg(has_associated_consts)]
pub trait OneConst: One {
/// Multiplicative identity: see [`One::one`](trait.One.html#tymethod.one).
const ONE: Self;
}
macro_rules! one_impl {
($t:ty, $v:expr) => {
impl One for $t {
@ -133,24 +179,39 @@ macro_rules! one_impl {
};
}
one_impl!(usize, 1);
one_impl!(u8, 1);
one_impl!(u16, 1);
one_impl!(u32, 1);
one_impl!(u64, 1);
#[cfg(has_i128)]
one_impl!(u128, 1);
#[cfg(has_associated_consts)]
macro_rules! one_const_impl {
($t:ty, $v:expr) => {
one_impl!($t, $v);
impl OneConst for $t {
const ONE: $t = $v;
}
};
}
#[cfg(not(has_associated_consts))]
macro_rules! one_const_impl {
($t:ty, $v:expr) => { one_impl!($t, $v); };
}
one_impl!(isize, 1);
one_impl!(i8, 1);
one_impl!(i16, 1);
one_impl!(i32, 1);
one_impl!(i64, 1);
#[cfg(has_i128)]
one_impl!(i128, 1);
one_impl!(f32, 1.0);
one_impl!(f64, 1.0);
one_const_impl!(usize, 1);
one_const_impl!(u8, 1);
one_const_impl!(u16, 1);
one_const_impl!(u32, 1);
one_const_impl!(u64, 1);
#[cfg(has_i128)]
one_const_impl!(u128, 1);
one_const_impl!(isize, 1);
one_const_impl!(i8, 1);
one_const_impl!(i16, 1);
one_const_impl!(i32, 1);
one_const_impl!(i64, 1);
#[cfg(has_i128)]
one_const_impl!(i128, 1);
one_const_impl!(f32, 1.0);
one_const_impl!(f64, 1.0);
impl<T: One> One for Wrapping<T>
where
@ -165,6 +226,14 @@ where
}
}
#[cfg(has_associated_consts)]
impl<T: OneConst> OneConst for Wrapping<T>
where
Wrapping<T>: One,
{
const ONE: Self = Wrapping(T::ONE);
}
// Some helper functions provided for backwards compatibility.
/// Returns the additive identity, `0`.
@ -179,6 +248,23 @@ pub fn one<T: One>() -> T {
One::one()
}
#[test]
#[cfg(has_associated_consts)]
fn const_identies() {
macro_rules! test_zero_one {
($zero:expr, $one:expr; $($t:ty),+) => {
$(
assert_eq!(<$t as ZeroConst>::ZERO, $zero);
assert_eq!(<$t as ZeroConst>::ZERO, <$t as Zero>::zero());
assert_eq!(<$t as OneConst>::ONE, $one);
assert_eq!(<$t as OneConst>::ONE, <$t as One>::one());
)+
}
}
test_zero_one!(0, 1; isize, i8, i16, i32, i64, usize, u8, u16, u32, u64);
test_zero_one!(0.0, 1.0; f32, f64);
}
#[test]
fn wrapping_identities() {
macro_rules! test_wrapping_identities {

View File

@ -32,6 +32,8 @@ pub use float::FloatConst;
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
pub use identities::{one, zero, One, Zero};
#[cfg(has_associated_consts)]
pub use identities::{OneConst, ZeroConst};
pub use int::PrimInt;
pub use ops::checked::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,