From a843027b563339034d2e3c98ecd8f0c38cd6ebd4 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Wed, 31 Jan 2018 15:42:55 -0800 Subject: [PATCH 1/7] Re-introduce the std feature This is a port of @vks's rust-num/num#296, but without the feature- toggled changes to `Float`. --- Cargo.toml | 4 ++++ src/bounds.rs | 8 ++++---- src/cast.rs | 13 +++++++------ src/identities.rs | 4 ++-- src/int.rs | 2 +- src/lib.rs | 24 +++++++++++++++--------- src/ops/checked.rs | 2 +- src/ops/wrapping.rs | 4 ++-- src/pow.rs | 2 +- src/sign.rs | 15 +++++++-------- 10 files changed, 44 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06cab57..a320050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ version = "0.1.42" readme = "README.md" [dependencies] + +[features] +default = ["std"] +std = [] diff --git a/src/bounds.rs b/src/bounds.rs index 83fdd0f..191f3e1 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -1,7 +1,7 @@ -use std::{usize, u8, u16, u32, u64}; -use std::{isize, i8, i16, i32, i64}; -use std::{f32, f64}; -use std::num::Wrapping; +use core::{usize, u8, u16, u32, u64}; +use core::{isize, i8, i16, i32, i64}; +use core::{f32, f64}; +use core::num::Wrapping; /// Numbers which have upper and lower bounds pub trait Bounded { diff --git a/src/cast.rs b/src/cast.rs index 2d7fe19..0ef0329 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,8 +1,9 @@ -use std::mem::size_of; -use std::num::Wrapping; +use core::mem::size_of; +use core::num::Wrapping; use identities::Zero; use bounds::Bounded; +use float::Float; /// A generic trait for converting a value to a number. pub trait ToPrimitive { @@ -226,8 +227,8 @@ macro_rules! impl_to_primitive_float_to_float { // Make sure the value is in range for the cast. // NaN and +-inf are cast as they are. let n = $slf as f64; - let max_value: $DstT = ::std::$DstT::MAX; - if !n.is_finite() || (-max_value as f64 <= n && n <= max_value as f64) { + let max_value: $DstT = ::core::$DstT::MAX; + if !Float::is_finite(n) || (-max_value as f64 <= n && n <= max_value as f64) { Some($slf as $DstT) } else { None @@ -522,8 +523,8 @@ impl_as_primitive!(bool => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64); #[test] fn to_primitive_float() { - use std::f32; - use std::f64; + use core::f32; + use core::f64; let f32_toolarge = 1e39f64; assert_eq!(f32_toolarge.to_f32(), None); diff --git a/src/identities.rs b/src/identities.rs index 79882ed..14f5ac0 100644 --- a/src/identities.rs +++ b/src/identities.rs @@ -1,5 +1,5 @@ -use std::ops::{Add, Mul}; -use std::num::Wrapping; +use core::ops::{Add, Mul}; +use core::num::Wrapping; /// Defines an additive identity element for `Self`. pub trait Zero: Sized + Add { diff --git a/src/int.rs b/src/int.rs index 4f9221f..84fedc6 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,4 @@ -use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; +use core::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use {Num, NumCast}; use bounds::Bounded; diff --git a/src/lib.rs b/src/lib.rs index 47c0bed..1413cc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,10 +12,16 @@ #![doc(html_root_url = "https://docs.rs/num-traits/0.1")] -use std::ops::{Add, Sub, Mul, Div, Rem}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::num::Wrapping; -use std::fmt; +#![deny(unconditional_recursion)] + +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] +extern crate core; + +use core::ops::{Add, Sub, Mul, Div, Rem}; +use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use core::num::Wrapping; +use core::fmt; pub use bounds::Bounded; pub use float::{Float, FloatConst}; @@ -130,10 +136,10 @@ impl NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {} macro_rules! int_trait_impl { ($name:ident for $($t:ty)*) => ($( impl $name for $t { - type FromStrRadixErr = ::std::num::ParseIntError; + type FromStrRadixErr = ::core::num::ParseIntError; #[inline] fn from_str_radix(s: &str, radix: u32) - -> Result + -> Result { <$t>::from_str_radix(s, radix) } @@ -159,7 +165,7 @@ pub enum FloatErrorKind { Empty, Invalid, } -// FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us, +// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us, // so there's not really any way for us to reuse it. #[derive(Debug)] pub struct ParseFloatError { @@ -317,8 +323,8 @@ macro_rules! float_trait_impl { }; match (is_positive, exp) { - (true, Ok(exp)) => base.powi(exp as i32), - (false, Ok(exp)) => 1.0 / base.powi(exp as i32), + (true, Ok(exp)) => Float::powi(base, exp as i32), + (false, Ok(exp)) => 1.0 / Float::powi(base, exp as i32), (_, Err(_)) => return Err(PFE { kind: Invalid }), } }, diff --git a/src/ops/checked.rs b/src/ops/checked.rs index 95214a2..020f649 100644 --- a/src/ops/checked.rs +++ b/src/ops/checked.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Sub, Mul, Div, Shl, Shr}; +use core::ops::{Add, Sub, Mul, Div, Shl, Shr}; /// Performs addition that returns `None` instead of wrapping around on /// overflow. diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index f989058..24f3405 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -1,5 +1,5 @@ -use std::ops::{Add, Sub, Mul}; -use std::num::Wrapping; +use core::ops::{Add, Sub, Mul}; +use core::num::Wrapping; macro_rules! wrapping_impl { ($trait_name:ident, $method:ident, $t:ty) => { diff --git a/src/pow.rs b/src/pow.rs index b250ad4..212a1de 100644 --- a/src/pow.rs +++ b/src/pow.rs @@ -1,4 +1,4 @@ -use std::ops::Mul; +use core::ops::Mul; use {One, CheckedMul}; /// Raises a value to the power of exp, using exponentiation by squaring. diff --git a/src/sign.rs b/src/sign.rs index 4b43c89..bf45bd8 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -1,8 +1,8 @@ -use std::ops::Neg; -use std::{f32, f64}; -use std::num::Wrapping; +use core::ops::Neg; +use core::{f32, f64}; +use core::num::Wrapping; -use Num; +use {Num, Float}; /// Useful functions for signed numbers (i.e. numbers that can be negative). pub trait Signed: Sized + Num + Neg { @@ -104,16 +104,15 @@ macro_rules! signed_float_impl { /// Computes the absolute value. Returns `NAN` if the number is `NAN`. #[inline] fn abs(&self) -> $t { - <$t>::abs(*self) + (*self).abs() } /// The positive difference of two numbers. Returns `0.0` if the number is /// less than or equal to `other`, otherwise the difference between`self` /// and `other` is returned. #[inline] - #[allow(deprecated)] fn abs_sub(&self, other: &$t) -> $t { - <$t>::abs_sub(*self, *other) + if *self <= *other { 0. } else { *self - *other } } /// # Returns @@ -123,7 +122,7 @@ macro_rules! signed_float_impl { /// - `NAN` if the number is NaN #[inline] fn signum(&self) -> $t { - <$t>::signum(*self) + Float::signum(*self) } /// Returns `true` if the number is positive, including `+0.0` and `INFINITY` From e6bb97b3ac5be8b18df07d095df1396d2cfc266b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 15:56:06 -0800 Subject: [PATCH 2/7] Make `Float` and `Real` depend on the `std` feature We don't have implementations for many of the methods in `no_std`. It's hostile to external implementors if some trait methods are conditional on a feature, as that feature could be added by anyone in a dependency tree. Instead, let's just live without these traits for now. --- src/cast.rs | 6 ++++-- src/float.rs | 20 +++++++++++++++++--- src/lib.rs | 35 ++++++++++++++++++++++------------- src/real.rs | 2 ++ src/sign.rs | 35 ++++++++++++++++++++++++++++++++++- 5 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index 0ef0329..9ac530b 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,9 +1,9 @@ +use core::f64; use core::mem::size_of; use core::num::Wrapping; use identities::Zero; use bounds::Bounded; -use float::Float; /// A generic trait for converting a value to a number. pub trait ToPrimitive { @@ -228,7 +228,9 @@ macro_rules! impl_to_primitive_float_to_float { // NaN and +-inf are cast as they are. let n = $slf as f64; let max_value: $DstT = ::core::$DstT::MAX; - if !Float::is_finite(n) || (-max_value as f64 <= n && n <= max_value as f64) { + if n != n || n == f64::INFINITY || n == f64::NEG_INFINITY + || (-max_value as f64 <= n && n <= max_value as f64) + { Some($slf as $DstT) } else { None diff --git a/src/float.rs b/src/float.rs index 3c8779a..3a7e931 100644 --- a/src/float.rs +++ b/src/float.rs @@ -1,15 +1,24 @@ +#[cfg(feature = "std")] use std::mem; +#[cfg(feature = "std")] use std::ops::Neg; +#[cfg(feature = "std")] use std::num::FpCategory; // Used for default implementation of `epsilon` +#[cfg(feature = "std")] use std::f32; +#[cfg(feature = "std")] use {Num, NumCast}; // FIXME: these doctests aren't actually helpful, because they're using and // testing the inherent methods directly, not going through `Float`. +/// Generic trait for floating point numbers +/// +/// This trait is only available with the `std` feature. +#[cfg(feature = "std")] pub trait Float : Num + Copy @@ -923,6 +932,7 @@ pub trait Float fn integer_decode(self) -> (u64, i16, i8); } +#[cfg(feature = "std")] macro_rules! float_impl { ($T:ident $decode:ident) => ( impl Float for $T { @@ -1219,6 +1229,7 @@ macro_rules! float_impl { ) } +#[cfg(feature = "std")] fn integer_decode_f32(f: f32) -> (u64, i16, i8) { let bits: u32 = unsafe { mem::transmute(f) }; let sign: i8 = if bits >> 31 == 0 { @@ -1237,6 +1248,7 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) { (mantissa as u64, exponent, sign) } +#[cfg(feature = "std")] fn integer_decode_f64(f: f64) -> (u64, i16, i8) { let bits: u64 = unsafe { mem::transmute(f) }; let sign: i8 = if bits >> 63 == 0 { @@ -1255,7 +1267,9 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) { (mantissa, exponent, sign) } +#[cfg(feature = "std")] float_impl!(f32 integer_decode_f32); +#[cfg(feature = "std")] float_impl!(f64 integer_decode_f64); macro_rules! float_const_impl { @@ -1272,7 +1286,7 @@ macro_rules! float_const_impl { $( #[inline] fn $constant() -> Self { - ::std::$T::consts::$constant + ::core::$T::consts::$constant } )+ } @@ -1314,13 +1328,13 @@ float_const_impl! { SQRT_2, } -#[cfg(test)] +#[cfg(all(test, feature = "std"))] mod tests { use Float; #[test] fn convert_deg_rad() { - use std::f64::consts; + use core::f64::consts; const DEG_RAD_PAIRS: [(f64, f64); 7] = [ (0.0, 0.), diff --git a/src/lib.rs b/src/lib.rs index 1413cc3..7e85647 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,9 @@ use core::num::Wrapping; use core::fmt; pub use bounds::Bounded; -pub use float::{Float, FloatConst}; +#[cfg(feature = "std")] +pub use float::Float; +pub use float::FloatConst; // pub use real::Real; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use identities::{Zero, One, zero, one}; pub use ops::checked::*; @@ -40,6 +42,7 @@ pub mod sign; pub mod ops; pub mod bounds; pub mod float; +#[cfg(feature = "std")] pub mod real; pub mod cast; pub mod int; @@ -187,7 +190,7 @@ impl fmt::Display for ParseFloatError { // with this implementation ourselves until we want to make a breaking change. // (would have to drop it from `Num` though) macro_rules! float_trait_impl { - ($name:ident for $($t:ty)*) => ($( + ($name:ident for $($t:ident)*) => ($( impl $name for $t { type FromStrRadixErr = ParseFloatError; @@ -199,9 +202,9 @@ macro_rules! float_trait_impl { // Special values match src { - "inf" => return Ok(Float::infinity()), - "-inf" => return Ok(Float::neg_infinity()), - "NaN" => return Ok(Float::nan()), + "inf" => return Ok(core::$t::INFINITY), + "-inf" => return Ok(core::$t::NEG_INFINITY), + "NaN" => return Ok(core::$t::NAN), _ => {}, } @@ -242,15 +245,15 @@ macro_rules! float_trait_impl { // if we've not seen any non-zero digits. if prev_sig != 0.0 { if is_positive && sig <= prev_sig - { return Ok(Float::infinity()); } + { return Ok(core::$t::INFINITY); } if !is_positive && sig >= prev_sig - { return Ok(Float::neg_infinity()); } + { return Ok(core::$t::NEG_INFINITY); } // Detect overflow by reversing the shift-and-add process if is_positive && (prev_sig != (sig - digit as $t) / radix as $t) - { return Ok(Float::infinity()); } + { return Ok(core::$t::INFINITY); } if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t) - { return Ok(Float::neg_infinity()); } + { return Ok(core::$t::NEG_INFINITY); } } prev_sig = sig; }, @@ -286,9 +289,9 @@ macro_rules! float_trait_impl { }; // Detect overflow by comparing to last value if is_positive && sig < prev_sig - { return Ok(Float::infinity()); } + { return Ok(core::$t::INFINITY); } if !is_positive && sig > prev_sig - { return Ok(Float::neg_infinity()); } + { return Ok(core::$t::NEG_INFINITY); } prev_sig = sig; }, None => match c { @@ -322,9 +325,15 @@ macro_rules! float_trait_impl { None => return Err(PFE { kind: Invalid }), }; + #[cfg(feature = "std")] + fn pow(base: $t, exp: usize) -> $t { + Float::powi(base, exp as i32) + } + // otherwise uses the generic `pow` from the root + match (is_positive, exp) { - (true, Ok(exp)) => Float::powi(base, exp as i32), - (false, Ok(exp)) => 1.0 / Float::powi(base, exp as i32), + (true, Ok(exp)) => pow(base, exp), + (false, Ok(exp)) => 1.0 / pow(base, exp), (_, Err(_)) => return Err(PFE { kind: Invalid }), } }, diff --git a/src/real.rs b/src/real.rs index c813a01..ab29d45 100644 --- a/src/real.rs +++ b/src/real.rs @@ -10,6 +10,8 @@ use {Num, NumCast, Float}; /// /// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type) /// for a list of data types that could meaningfully implement this trait. +/// +/// This trait is only available with the `std` feature. pub trait Real : Num + Copy diff --git a/src/sign.rs b/src/sign.rs index bf45bd8..f5769ab 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -2,7 +2,7 @@ use core::ops::Neg; use core::{f32, f64}; use core::num::Wrapping; -use {Num, Float}; +use Num; /// Useful functions for signed numbers (i.e. numbers that can be negative). pub trait Signed: Sized + Num + Neg { @@ -103,10 +103,24 @@ macro_rules! signed_float_impl { impl Signed for $t { /// Computes the absolute value. Returns `NAN` if the number is `NAN`. #[inline] + #[cfg(feature = "std")] fn abs(&self) -> $t { (*self).abs() } + /// Computes the absolute value. Returns `NAN` if the number is `NAN`. + #[inline] + #[cfg(not(feature = "std"))] + fn abs(&self) -> $t { + if self.is_positive() { + *self + } else if self.is_negative() { + -*self + } else { + $nan + } + } + /// The positive difference of two numbers. Returns `0.0` if the number is /// less than or equal to `other`, otherwise the difference between`self` /// and `other` is returned. @@ -121,10 +135,29 @@ macro_rules! signed_float_impl { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is NaN #[inline] + #[cfg(feature = "std")] fn signum(&self) -> $t { + use Float; Float::signum(*self) } + /// # Returns + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is NaN + #[inline] + #[cfg(not(feature = "std"))] + fn signum(&self) -> $t { + if self.is_positive() { + 1.0 + } else if self.is_negative() { + -1.0 + } else { + $nan + } + } + /// Returns `true` if the number is positive, including `+0.0` and `INFINITY` #[inline] fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf } From 79786ac518db2f08e87aa05bce17b8d0a1626a2b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 15:56:25 -0800 Subject: [PATCH 3/7] test no_std in CI --- ci/test_full.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/test_full.sh b/ci/test_full.sh index c64610f..1c09079 100755 --- a/ci/test_full.sh +++ b/ci/test_full.sh @@ -8,4 +8,6 @@ echo Testing num-traits on rustc ${TRAVIS_RUST_VERSION} cargo build --verbose cargo test --verbose -# We have no features to test... +# test `no_std` +cargo build --verbose --no-default-features +cargo test --verbose --no-default-features From 4fbc583eb998574defdf6584027ec3b5cec19cab Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 16:05:43 -0800 Subject: [PATCH 4/7] Don't use wildcards for pub use --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7e85647..80227b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,11 +29,11 @@ pub use float::Float; pub use float::FloatConst; // pub use real::Real; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use identities::{Zero, One, zero, one}; -pub use ops::checked::*; -pub use ops::wrapping::*; +pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr}; +pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub}; pub use ops::saturating::Saturating; pub use sign::{Signed, Unsigned, abs, abs_sub, signum}; -pub use cast::*; +pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast}; pub use int::PrimInt; pub use pow::{pow, checked_pow}; From 36b2514f4b91317cc3117533f0a81b00887ebb51 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 16:16:41 -0800 Subject: [PATCH 5/7] Note the std feature in README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index b1491b1..a701728 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,19 @@ and this to your crate root: extern crate num_traits; ``` +## Features + +This crate can be used without the standard library (`#![no_std]`) by disabling +the default `std` feature. Use this in `Cargo.toml`: + +```toml +[dependencies.num-traits] +version = "0.1" +default-features = false +``` + +The `Float` and `Real` traits are only available when `std` is enabled. + ## Releases Release notes are available in [RELEASES.md](RELEASES.md). From 67f03391a1ab89fbf71262371903072c454fc71c Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 16:19:00 -0800 Subject: [PATCH 6/7] Bump to 0.2 for the breaking feature change --- Cargo.toml | 2 +- README.md | 4 ++-- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a320050..e37d337 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = [ "algorithms", "science" ] license = "MIT/Apache-2.0" repository = "https://github.com/rust-num/num-traits" name = "num-traits" -version = "0.1.42" +version = "0.2.0-pre" readme = "README.md" [dependencies] diff --git a/README.md b/README.md index a701728..5f0c236 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -num-traits = "0.1" +num-traits = "0.2" ``` and this to your crate root: @@ -28,7 +28,7 @@ the default `std` feature. Use this in `Cargo.toml`: ```toml [dependencies.num-traits] -version = "0.1" +version = "0.2" default-features = false ``` diff --git a/src/lib.rs b/src/lib.rs index 80227b4..ef96e5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! Numeric traits for generic mathematics -#![doc(html_root_url = "https://docs.rs/num-traits/0.1")] +#![doc(html_root_url = "https://docs.rs/num-traits/0.2")] #![deny(unconditional_recursion)] From ffa67c8527ef38145780c13a7594e0901706665c Mon Sep 17 00:00:00 2001 From: Toshiki Teramura Date: Thu, 1 Feb 2018 11:56:13 -0800 Subject: [PATCH 7/7] CI typo fix --- ci/test_full.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test_full.sh b/ci/test_full.sh index 1c09079..c86c178 100755 --- a/ci/test_full.sh +++ b/ci/test_full.sh @@ -4,7 +4,7 @@ set -ex echo Testing num-traits on rustc ${TRAVIS_RUST_VERSION} -# num-integer should build and test everywhere. +# num-traits should build and test everywhere. cargo build --verbose cargo test --verbose