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:
parent
4ab251b0a2
commit
b9c4311fea
|
@ -22,3 +22,4 @@ features = ["std"]
|
|||
default = ["std"]
|
||||
std = []
|
||||
i128 = []
|
||||
associated_consts = []
|
||||
|
|
|
@ -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).
|
||||
|
|
10
build.rs
10
build.rs
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue