Bug 1910779 - Update num-traits to 0.2.19. r=supply-chain-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D218147
This commit is contained in:
Mike Hommey
2024-07-31 02:49:35 +00:00
parent 81c8430aee
commit bbe3469503
25 changed files with 916 additions and 584 deletions

4
Cargo.lock generated
View File

@@ -4304,9 +4304,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.15"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",

View File

@@ -1021,6 +1021,12 @@ criteria = "safe-to-deploy"
delta = "0.8.6 -> 0.8.8"
notes = "Mostly OS portability updates along with some minor bugfixes."
[[audits.bytecode-alliance.audits.num-traits]]
who = "Andrew Brown <andrew.brown@intel.com>"
criteria = "safe-to-deploy"
version = "0.2.19"
notes = "As advertised: a numeric library. The only `unsafe` is from some float-to-int conversions, which seems expected."
[[audits.bytecode-alliance.audits.object]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"5b2749641deeabb2dfcc8e4d7e26ccfbc306800021e0d24e8367f313e57f9def","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"81e7df6fa6bea6f8c2809f9af68e3d32e7a4504b93394f775d37ed3d9f7f9166","RELEASES.md":"e1f774cba66e5e15e1086ab8afebece771140dd4168f59dca8dd4fd5e50b72dc","build.rs":"cf682b2322303196e241048cb56d873597b78a3b4e3f275f6f761dadb33a65f5","src/bounds.rs":"c90190de4dfba13c49119dbdf889726f8ece1cbd7dfd4bbfa364ea995f627e49","src/cast.rs":"8c8384dcdfaf926b9331399d528278fc73851f8b5e1105dee343f4f19557e932","src/float.rs":"6a84820f4828515639565848a63359b3e69329aa36b990178adbfc7d141ef0c5","src/identities.rs":"5b6238ebd52e1fadd5b405bc40ad81e45346bcb1c4b46cf1f0496a30be7c9bc4","src/int.rs":"bb4c0f4ce8d71e262bd9119ab820dd5a79e2bd476a8ad7e84b2167733b11d9d8","src/lib.rs":"cc0c8352b3f29a22b17f76e9cfe12acb279ec2aac5e22a9395569d58445c137c","src/macros.rs":"ee96613a2c73a3bef10ec7ae4d359dbf5f0b41f83e8a87c3d62ccc18dd27e498","src/ops/checked.rs":"b6dfae21fe1a5ce41e92074c57d204284975ec56d45e63cac5f0136b8c3643b4","src/ops/euclid.rs":"71e0e181bd365c196a7dea980c2ec8bd47fd1d1d9b47bd3f401edcadb861eb0b","src/ops/inv.rs":"dd80b9bd48d815f17855a25842287942317fa49d1fdcdd655b61bd20ef927cda","src/ops/mod.rs":"3bea8b98fa7537c0a5b4562d1b9d4d49481f1e2e88941cfd4cc8f0f3f0870fb3","src/ops/mul_add.rs":"368bdebb40b16f3b4b85cf50235954268ff601ec7a458a3a83fe433f47f86f6d","src/ops/overflowing.rs":"1b92882a5a738ea4cafdb0971101dc438be9043f540e1246f58f7c9ecf6348dc","src/ops/saturating.rs":"6fb4b2a2c78d9202152a84586d7b068444b78d3caed4b293980832672a234d4b","src/ops/wrapping.rs":"0acf88c0e5fc81a3c6790b31986ab9be5b16c720c9e27461fe5d69b710ffcaba","src/pow.rs":"9f78cb9c4d5987b59e16f4141723a33ff689781cc352f357b0cc0111d22cde3a","src/real.rs":"b5115bb2cfb752a59426bb3fcbabf9cff15521a00a3f8b5ef4dfc0b0b31bb1f4","src/sign.rs":"83562caa3501c6873558eb64c9e3bfe25b4b20d38562a7aa7cc9adafcb3ff037","tests/cast.rs":"0a41785611b3909ecb4a88d6d5264a85564f6de8fbfc761436d3c8baafc8e3d0"},"package":"578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"}
{"files":{"Cargo.toml":"dd701a0da6cce7e6e047cc944b2330f3c5e48cd64329e10942ea7d9299d435be","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"3fa9b7a124e7bc011758919f6d13fbdce58027852abc6c0851ddf6addfedabd5","RELEASES.md":"eb3298353c12e0cd48c79437199bd7f159c4250da06f8362afcf71004e98fde5","build.rs":"d3969209fc1c9d201c66ed11820d0b328600d75b3971f8ceebeab04900bc0587","src/bounds.rs":"a79325f6a92269ad7df3d11b9ff700d2d13fb1160e28f0c091a644efc4badc2b","src/cast.rs":"d2c9337163c3d594a701bfce21aec56571625fa0117f970f14fd82dcc4504bf6","src/float.rs":"2caf20ca3227422dcd8981accc79898e889bbda97fce1fc7f881c98e7091d8c3","src/identities.rs":"c26d7f2fd6636721930d11d345e0c7103b0a4ac242dc4035dbc956a45eba422f","src/int.rs":"ca214bab6624cb7f19bcb439958aa34596e0b13d8fc9b0090a7b37e89946d124","src/lib.rs":"00973c9c52fd607d6e4b1da4ce4d5caa7d1bc39c8cd6f5d64878075766c8ad33","src/macros.rs":"ee96613a2c73a3bef10ec7ae4d359dbf5f0b41f83e8a87c3d62ccc18dd27e498","src/ops/bytes.rs":"24ade942062566d686c6de5674b5668ea3cd688c7c88bd8e5df7ea7f96d70c6e","src/ops/checked.rs":"01e6379bf1d8eeca9dcf8bb5397e419e898e4043b57b0e2470e225bc27e81e6a","src/ops/euclid.rs":"89c09c2df7fcc4bdba32533d4e7254dceb424085239544ea2a9ae8a606bf7383","src/ops/inv.rs":"dd80b9bd48d815f17855a25842287942317fa49d1fdcdd655b61bd20ef927cda","src/ops/mod.rs":"2b3c396af44cd240205ba8b560625fa00c07cf387139d2c49eeb7869545d976d","src/ops/mul_add.rs":"15bd64d9420c86300c5ea7f57aa736af2ef968e4e5eaaae03f62fd277f124569","src/ops/overflowing.rs":"01f4cd27f8b0e257687170cc537188029e08e5d13e0c552b01153be5d66d5716","src/ops/saturating.rs":"165993c829c10c4f60e32c8cf34434b669ef54284d7f73dc7ec58a22ba65e6fc","src/ops/wrapping.rs":"39d7bc7e074ba7590cd29b40206baed9cb30ae70dca2b7ceb460c6ca7eaad2a8","src/pow.rs":"92c12990d2396b2dabd4ba80e80ad706c0c8fd0f1b967ab3bdd9cb738b150702","src/real.rs":"b45bc1ca54549595c8d4f91a0e192769c1d924b40eda3446af4780f7a07ac8ed","src/sign.rs":"7ca11eebee94b553a33a9e53b7663ba5173db297dee523d1a2600fbbc80ef850","tests/cast.rs":"6fcc0d6653253182e979e42542fe971829cd24ab2c3a21a668e935c23d39f7c0"},"package":"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"}

View File

@@ -10,12 +10,13 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.60"
name = "num-traits"
version = "0.2.15"
version = "0.2.19"
authors = ["The Rust Project Developers"]
build = "build.rs"
exclude = [
"/bors.toml",
"/ci/*",
"/.github/*",
]
@@ -37,6 +38,7 @@ repository = "https://github.com/rust-num/num-traits"
[package.metadata.docs.rs]
features = ["std"]
rustdoc-args = ["--generate-link-to-definition"]
[dependencies.libm]
version = "0.2.0"
@@ -48,4 +50,5 @@ version = "1"
[features]
default = ["std"]
i128 = []
libm = ["dep:libm"]
std = []

View File

@@ -2,7 +2,7 @@
[![crate](https://img.shields.io/crates/v/num-traits.svg)](https://crates.io/crates/num-traits)
[![documentation](https://docs.rs/num-traits/badge.svg)](https://docs.rs/num-traits)
[![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![minimum rustc 1.60](https://img.shields.io/badge/rustc-1.60+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![build status](https://github.com/rust-num/num-traits/workflows/master/badge.svg)](https://github.com/rust-num/num-traits/actions)
Numeric traits for generic mathematics in Rust.
@@ -28,24 +28,19 @@ default-features = false
# features = ["libm"] # <--- Uncomment if you wish to use `Float` and `Real` without `std`
```
The `Float` and `Real` traits are only available when either `std` or `libm` is enabled.
The `libm` feature is only available with Rust 1.31 and later ([see PR #99](https://github.com/rust-num/num-traits/pull/99)).
The `Float` and `Real` traits are only available when either `std` or `libm` is enabled.
The `FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
and `f64` also require `std` or `libm`, as do implementations of signed and floating-
point exponents in `Pow`.
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.
## Releases
Release notes are available in [RELEASES.md](RELEASES.md).
## Compatibility
The `num-traits` crate is tested for rustc 1.8 and greater.
The `num-traits` crate is tested for rustc 1.60 and greater.
## License

View File

@@ -1,3 +1,51 @@
# Release 0.2.19 (2024-05-03)
- [Upgrade to 2021 edition, **MSRV 1.60**][310]
- [The new `Float::clamp` limits values by minimum and maximum][305]
**Contributors**: @cuviper, @michaelciraci
[305]: https://github.com/rust-num/num-traits/pull/305
[310]: https://github.com/rust-num/num-traits/pull/310
# Release 0.2.18 (2024-02-07)
- [The new `Euclid::div_rem_euclid` and `CheckedEuclid::checked_div_rem_euclid` methods][291]
compute and return the quotient and remainder at the same time.
- [The new `TotalOrder` trait implements the IEEE 754 `totalOrder` predicate.][295]
- [The new `ConstZero` and `ConstOne` traits offered associated constants][303],
extending the non-const `Zero` and `One` traits for types that have constant values.
**Contributors**: @andrewjradcliffe, @cuviper, @tarcieri, @tdelabro, @waywardmonkeys
[291]: https://github.com/rust-num/num-traits/pull/291
[295]: https://github.com/rust-num/num-traits/pull/295
[303]: https://github.com/rust-num/num-traits/pull/303
# Release 0.2.17 (2023-10-07)
- [Fix a doc warning about custom classes with newer rustdoc.][286]
**Contributors**: @robamu
[286]: https://github.com/rust-num/num-traits/pull/286
# Release 0.2.16 (2023-07-20)
- [Upgrade to 2018 edition, **MSRV 1.31**][240]
- [The new `ToBytes` and `FromBytes` traits][224] convert to and from byte
representations of a value, with little, big, and native-endian options.
- [The new `Float::is_subnormal` method checks for subnormal values][279], with
a non-zero magnitude that is less than the normal minimum positive value.
- Several other improvements to documentation and testing.
**Contributors**: @ctrlcctrlv, @cuviper, @flier, @GuillaumeGomez, @kaidokert,
@rs017991, @vicsn
[224]: https://github.com/rust-num/num-traits/pull/224
[240]: https://github.com/rust-num/num-traits/pull/240
[279]: https://github.com/rust-num/num-traits/pull/279
# Release 0.2.15 (2022-05-02)
- [The new `Euclid` trait calculates Euclidean division][195], where the

View File

@@ -1,29 +1,7 @@
extern crate autocfg;
use std::env;
fn main() {
let ac = autocfg::new();
// If the "i128" feature is explicity requested, don't bother probing for it.
// It will still cause a build error if that was set improperly.
if env::var_os("CARGO_FEATURE_I128").is_some() || ac.probe_type("i128") {
autocfg::emit("has_i128");
}
ac.emit_expression_cfg(
"unsafe { 1f64.to_int_unchecked::<i32>() }",
"has_to_int_unchecked",
);
ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits");
ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones");
ac.emit_expression_cfg("{ let mut x = 1; x += &2; }", "has_int_assignop_ref");
ac.emit_expression_cfg("1u32.div_euclid(1u32)", "has_div_euclid");
if env::var_os("CARGO_FEATURE_STD").is_some() {
ac.emit_expression_cfg("1f64.copysign(-1f64)", "has_copysign");
}
ac.emit_expression_cfg("1f64.total_cmp(&2f64)", "has_total_cmp"); // 1.62
autocfg::rerun_path("build.rs");
}

View File

@@ -1,9 +1,7 @@
use core::num::Wrapping;
use core::{f32, f64};
#[cfg(has_i128)]
use core::{i128, u128};
use core::{i16, i32, i64, i8, isize};
use core::{u16, u32, u64, u8, usize};
use core::{i128, i16, i32, i64, i8, isize};
use core::{u128, u16, u32, u64, u8, usize};
/// Numbers which have upper and lower bounds
pub trait Bounded {
@@ -61,7 +59,6 @@ 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);
bounded_impl!(isize, isize::MIN, isize::MAX);
@@ -69,7 +66,6 @@ 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);
#[cfg(has_i128)]
bounded_impl!(i128, i128::MIN, i128::MAX);
impl<T: Bounded> Bounded for Wrapping<T> {
@@ -130,7 +126,6 @@ fn wrapping_bounded() {
test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
}
#[cfg(has_i128)]
#[test]
fn wrapping_bounded_i128() {
macro_rules! test_wrapping_bounded {

View File

@@ -1,10 +1,8 @@
use core::mem::size_of;
use core::num::Wrapping;
use core::{f32, f64};
#[cfg(has_i128)]
use core::{i128, u128};
use core::{i16, i32, i64, i8, isize};
use core::{u16, u32, u64, u8, usize};
use core::{i128, i16, i32, i64, i8, isize};
use core::{u128, u16, u32, u64, u8, usize};
/// A generic trait for converting a value to a number.
///
@@ -53,12 +51,9 @@ pub trait ToPrimitive {
/// represented by an `i128` (`i64` under the default implementation), then
/// `None` is returned.
///
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
///
/// The default implementation converts through `to_i64()`. Types implementing
/// this trait should override this method if they can represent a greater range.
#[inline]
#[cfg(has_i128)]
fn to_i128(&self) -> Option<i128> {
self.to_i64().map(From::from)
}
@@ -99,12 +94,9 @@ pub trait ToPrimitive {
/// represented by a `u128` (`u64` under the default implementation), then
/// `None` is returned.
///
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
///
/// The default implementation converts through `to_u64()`. Types implementing
/// this trait should override this method if they can represent a greater range.
#[inline]
#[cfg(has_i128)]
fn to_u128(&self) -> Option<u128> {
self.to_u64().map(From::from)
}
@@ -173,7 +165,6 @@ macro_rules! impl_to_primitive_int {
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
@@ -183,7 +174,6 @@ macro_rules! impl_to_primitive_int {
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
@@ -204,7 +194,6 @@ impl_to_primitive_int!(i8);
impl_to_primitive_int!(i16);
impl_to_primitive_int!(i32);
impl_to_primitive_int!(i64);
#[cfg(has_i128)]
impl_to_primitive_int!(i128);
macro_rules! impl_to_primitive_uint_to_int {
@@ -246,7 +235,6 @@ macro_rules! impl_to_primitive_uint {
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
@@ -256,7 +244,6 @@ macro_rules! impl_to_primitive_uint {
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
@@ -277,7 +264,6 @@ impl_to_primitive_uint!(u8);
impl_to_primitive_uint!(u16);
impl_to_primitive_uint!(u32);
impl_to_primitive_uint!(u64);
#[cfg(has_i128)]
impl_to_primitive_uint!(u128);
macro_rules! impl_to_primitive_float_to_float {
@@ -291,7 +277,6 @@ macro_rules! impl_to_primitive_float_to_float {
)*}
}
#[cfg(has_to_int_unchecked)]
macro_rules! float_to_int_unchecked {
// SAFETY: Must not be NaN or infinite; must be representable as the integer after truncating.
// We already checked that the float is in the exclusive range `(MIN-1, MAX+1)`.
@@ -300,13 +285,6 @@ macro_rules! float_to_int_unchecked {
};
}
#[cfg(not(has_to_int_unchecked))]
macro_rules! float_to_int_unchecked {
($float:expr => $int:ty) => {
$float as $int
};
}
macro_rules! impl_to_primitive_float_to_signed_int {
($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
#[inline]
@@ -373,7 +351,6 @@ macro_rules! impl_to_primitive_float {
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
@@ -383,7 +360,6 @@ macro_rules! impl_to_primitive_float {
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
@@ -444,12 +420,9 @@ pub trait FromPrimitive: Sized {
/// Converts an `i128` to return an optional value of this type. If the
/// value cannot be represented by this type, then `None` is returned.
///
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
///
/// The default implementation converts through `from_i64()`. Types implementing
/// this trait should override this method if they can represent a greater range.
#[inline]
#[cfg(has_i128)]
fn from_i128(n: i128) -> Option<Self> {
n.to_i64().and_then(FromPrimitive::from_i64)
}
@@ -489,12 +462,9 @@ pub trait FromPrimitive: Sized {
/// Converts an `u128` to return an optional value of this type. If the
/// value cannot be represented by this type, then `None` is returned.
///
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
///
/// The default implementation converts through `from_u64()`. Types implementing
/// this trait should override this method if they can represent a greater range.
#[inline]
#[cfg(has_i128)]
fn from_u128(n: u128) -> Option<Self> {
n.to_u64().and_then(FromPrimitive::from_u64)
}
@@ -545,7 +515,6 @@ macro_rules! impl_from_primitive {
fn from_i64(n: i64) -> Option<$T> {
n.$to_ty()
}
#[cfg(has_i128)]
#[inline]
fn from_i128(n: i128) -> Option<$T> {
n.$to_ty()
@@ -571,7 +540,6 @@ macro_rules! impl_from_primitive {
fn from_u64(n: u64) -> Option<$T> {
n.$to_ty()
}
#[cfg(has_i128)]
#[inline]
fn from_u128(n: u128) -> Option<$T> {
n.$to_ty()
@@ -594,14 +562,12 @@ impl_from_primitive!(i8, to_i8);
impl_from_primitive!(i16, to_i16);
impl_from_primitive!(i32, to_i32);
impl_from_primitive!(i64, to_i64);
#[cfg(has_i128)]
impl_from_primitive!(i128, to_i128);
impl_from_primitive!(usize, to_usize);
impl_from_primitive!(u8, to_u8);
impl_from_primitive!(u16, to_u16);
impl_from_primitive!(u32, to_u32);
impl_from_primitive!(u64, to_u64);
#[cfg(has_i128)]
impl_from_primitive!(u128, to_u128);
impl_from_primitive!(f32, to_f32);
impl_from_primitive!(f64, to_f64);
@@ -623,7 +589,6 @@ impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
fn to_usize -> usize;
@@ -631,7 +596,6 @@ impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
fn to_f32 -> f32;
@@ -656,7 +620,6 @@ impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
fn from_i16(i16);
fn from_i32(i32);
fn from_i64(i64);
#[cfg(has_i128)]
fn from_i128(i128);
fn from_usize(usize);
@@ -664,7 +627,6 @@ impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
fn from_u16(u16);
fn from_u32(u32);
fn from_u64(u64);
#[cfg(has_i128)]
fn from_u128(u128);
fn from_f32(f32);
@@ -722,14 +684,12 @@ impl_num_cast!(u8, to_u8);
impl_num_cast!(u16, to_u16);
impl_num_cast!(u32, to_u32);
impl_num_cast!(u64, to_u64);
#[cfg(has_i128)]
impl_num_cast!(u128, to_u128);
impl_num_cast!(usize, to_usize);
impl_num_cast!(i8, to_i8);
impl_num_cast!(i16, to_i16);
impl_num_cast!(i32, to_i32);
impl_num_cast!(i64, to_i64);
#[cfg(has_i128)]
impl_num_cast!(i128, to_i128);
impl_num_cast!(isize, to_isize);
impl_num_cast!(f32, to_f32);
@@ -787,10 +747,8 @@ macro_rules! impl_as_primitive {
)*};
($T: ty => { $( $U: ty ),* } ) => {
impl_as_primitive!(@ $T => { $( $U ),* });
impl_as_primitive!(@ $T => { u8, u16, u32, u64, usize });
impl_as_primitive!(@ $T => #[cfg(has_i128)] impl u128);
impl_as_primitive!(@ $T => { i8, i16, i32, i64, isize });
impl_as_primitive!(@ $T => #[cfg(has_i128)] impl i128);
impl_as_primitive!(@ $T => { u8, u16, u32, u64, u128, usize });
impl_as_primitive!(@ $T => { i8, i16, i32, i64, i128, isize });
};
}
@@ -802,9 +760,7 @@ impl_as_primitive!(u32 => { f32, f64 });
impl_as_primitive!(i32 => { f32, f64 });
impl_as_primitive!(u64 => { f32, f64 });
impl_as_primitive!(i64 => { f32, f64 });
#[cfg(has_i128)]
impl_as_primitive!(u128 => { f32, f64 });
#[cfg(has_i128)]
impl_as_primitive!(i128 => { f32, f64 });
impl_as_primitive!(usize => { f32, f64 });
impl_as_primitive!(isize => { f32, f64 });

View File

@@ -1,14 +1,11 @@
use core::mem;
use core::cmp::Ordering;
use core::num::FpCategory;
use core::ops::{Add, Div, Neg};
use core::f32;
use core::f64;
use {Num, NumCast, ToPrimitive};
#[cfg(all(not(feature = "std"), feature = "libm"))]
use libm;
use crate::{Num, NumCast, ToPrimitive};
/// Generic trait for floating point numbers that works with `no_std`.
///
@@ -170,6 +167,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
/// check(0.0f64, false);
/// ```
#[inline]
#[allow(clippy::eq_op)]
fn is_nan(self) -> bool {
self != self
}
@@ -244,6 +242,32 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
self.classify() == FpCategory::Normal
}
/// Returns `true` if the number is [subnormal].
///
/// ```
/// use num_traits::float::FloatCore;
/// use std::f64;
///
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
/// let max = f64::MAX;
/// let lower_than_min = 1.0e-308_f64;
/// let zero = 0.0_f64;
///
/// assert!(!min.is_subnormal());
/// assert!(!max.is_subnormal());
///
/// assert!(!zero.is_subnormal());
/// assert!(!f64::NAN.is_subnormal());
/// assert!(!f64::INFINITY.is_subnormal());
/// // Values between `0` and `min` are Subnormal.
/// assert!(lower_than_min.is_subnormal());
/// ```
/// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
#[inline]
fn is_subnormal(self) -> bool {
self.classify() == FpCategory::Subnormal
}
/// Returns the floating point category of the number. If only one property
/// is going to be tested, it is generally faster to use the specific
/// predicate instead.
@@ -370,12 +394,10 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
} else {
self - f + one
}
} else if -f < h {
self - f
} else {
if -f < h {
self - f
} else {
self - f - one
}
self - f - one
}
}
@@ -508,8 +530,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
}
/// Returns `true` if `self` is positive, including `+0.0` and
/// `FloatCore::infinity()`, and since Rust 1.20 also
/// `FloatCore::nan()`.
/// `FloatCore::infinity()`, and `FloatCore::nan()`.
///
/// # Examples
///
@@ -527,6 +548,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
/// check(-0.0f64, false);
/// check(f64::NEG_INFINITY, false);
/// check(f64::MIN_POSITIVE, true);
/// check(f64::NAN, true);
/// check(-f64::NAN, false);
/// ```
#[inline]
@@ -535,8 +557,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
}
/// Returns `true` if `self` is negative, including `-0.0` and
/// `FloatCore::neg_infinity()`, and since Rust 1.20 also
/// `-FloatCore::nan()`.
/// `FloatCore::neg_infinity()`, and `-FloatCore::nan()`.
///
/// # Examples
///
@@ -555,6 +576,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
/// check(f64::NEG_INFINITY, true);
/// check(f64::MIN_POSITIVE, false);
/// check(f64::NAN, false);
/// check(-f64::NAN, true);
/// ```
#[inline]
fn is_sign_negative(self) -> bool {
@@ -630,6 +652,36 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
}
}
/// A value bounded by a minimum and a maximum
///
/// If input is less than min then this returns min.
/// If input is greater than max then this returns max.
/// Otherwise this returns input.
///
/// **Panics** in debug mode if `!(min <= max)`.
///
/// # Examples
///
/// ```
/// use num_traits::float::FloatCore;
///
/// fn check<T: FloatCore>(val: T, min: T, max: T, expected: T) {
/// assert!(val.clamp(min, max) == expected);
/// }
///
///
/// check(1.0f32, 0.0, 2.0, 1.0);
/// check(1.0f32, 2.0, 3.0, 2.0);
/// check(3.0f32, 0.0, 2.0, 2.0);
///
/// check(1.0f64, 0.0, 2.0, 1.0);
/// check(1.0f64, 2.0, 3.0, 2.0);
/// check(3.0f64, 0.0, 2.0, 2.0);
/// ```
fn clamp(self, min: Self, max: Self) -> Self {
crate::clamp(self, min, max)
}
/// Returns the reciprocal (multiplicative inverse) of the number.
///
/// # Examples
@@ -763,56 +815,25 @@ impl FloatCore for f32 {
integer_decode_f32(self)
}
#[inline]
#[cfg(not(feature = "std"))]
fn classify(self) -> FpCategory {
const EXP_MASK: u32 = 0x7f800000;
const MAN_MASK: u32 = 0x007fffff;
// Safety: this identical to the implementation of f32::to_bits(),
// which is only available starting at Rust 1.20
let bits: u32 = unsafe { mem::transmute(self) };
match (bits & MAN_MASK, bits & EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
#[inline]
#[cfg(not(feature = "std"))]
fn is_sign_negative(self) -> bool {
const SIGN_MASK: u32 = 0x80000000;
// Safety: this identical to the implementation of f32::to_bits(),
// which is only available starting at Rust 1.20
let bits: u32 = unsafe { mem::transmute(self) };
bits & SIGN_MASK != 0
}
#[inline]
#[cfg(not(feature = "std"))]
fn to_degrees(self) -> Self {
// Use a constant for better precision.
const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
self * PIS_IN_180
}
#[inline]
#[cfg(not(feature = "std"))]
fn to_radians(self) -> Self {
self * (f32::consts::PI / 180.0)
}
#[cfg(feature = "std")]
forward! {
Self::is_nan(self) -> bool;
Self::is_infinite(self) -> bool;
Self::is_finite(self) -> bool;
Self::is_normal(self) -> bool;
Self::is_subnormal(self) -> bool;
Self::clamp(self, min: Self, max: Self) -> Self;
Self::classify(self) -> FpCategory;
Self::is_sign_positive(self) -> bool;
Self::is_sign_negative(self) -> bool;
Self::min(self, other: Self) -> Self;
Self::max(self, other: Self) -> Self;
Self::recip(self) -> Self;
Self::to_degrees(self) -> Self;
Self::to_radians(self) -> Self;
}
#[cfg(feature = "std")]
forward! {
Self::floor(self) -> Self;
Self::ceil(self) -> Self;
Self::round(self) -> Self;
@@ -820,14 +841,7 @@ impl FloatCore for f32 {
Self::fract(self) -> Self;
Self::abs(self) -> Self;
Self::signum(self) -> Self;
Self::is_sign_positive(self) -> bool;
Self::is_sign_negative(self) -> bool;
Self::min(self, other: Self) -> Self;
Self::max(self, other: Self) -> Self;
Self::recip(self) -> Self;
Self::powi(self, n: i32) -> Self;
Self::to_degrees(self) -> Self;
Self::to_radians(self) -> Self;
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -837,8 +851,6 @@ impl FloatCore for f32 {
libm::roundf as round(self) -> Self;
libm::truncf as trunc(self) -> Self;
libm::fabsf as abs(self) -> Self;
libm::fminf as min(self, other: Self) -> Self;
libm::fmaxf as max(self, other: Self) -> Self;
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -865,57 +877,25 @@ impl FloatCore for f64 {
integer_decode_f64(self)
}
#[inline]
#[cfg(not(feature = "std"))]
fn classify(self) -> FpCategory {
const EXP_MASK: u64 = 0x7ff0000000000000;
const MAN_MASK: u64 = 0x000fffffffffffff;
// Safety: this identical to the implementation of f64::to_bits(),
// which is only available starting at Rust 1.20
let bits: u64 = unsafe { mem::transmute(self) };
match (bits & MAN_MASK, bits & EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
#[inline]
#[cfg(not(feature = "std"))]
fn is_sign_negative(self) -> bool {
const SIGN_MASK: u64 = 0x8000000000000000;
// Safety: this identical to the implementation of f64::to_bits(),
// which is only available starting at Rust 1.20
let bits: u64 = unsafe { mem::transmute(self) };
bits & SIGN_MASK != 0
}
#[inline]
#[cfg(not(feature = "std"))]
fn to_degrees(self) -> Self {
// The division here is correctly rounded with respect to the true
// value of 180/π. (This differs from f32, where a constant must be
// used to ensure a correctly rounded result.)
self * (180.0 / f64::consts::PI)
}
#[inline]
#[cfg(not(feature = "std"))]
fn to_radians(self) -> Self {
self * (f64::consts::PI / 180.0)
}
#[cfg(feature = "std")]
forward! {
Self::is_nan(self) -> bool;
Self::is_infinite(self) -> bool;
Self::is_finite(self) -> bool;
Self::is_normal(self) -> bool;
Self::is_subnormal(self) -> bool;
Self::clamp(self, min: Self, max: Self) -> Self;
Self::classify(self) -> FpCategory;
Self::is_sign_positive(self) -> bool;
Self::is_sign_negative(self) -> bool;
Self::min(self, other: Self) -> Self;
Self::max(self, other: Self) -> Self;
Self::recip(self) -> Self;
Self::to_degrees(self) -> Self;
Self::to_radians(self) -> Self;
}
#[cfg(feature = "std")]
forward! {
Self::floor(self) -> Self;
Self::ceil(self) -> Self;
Self::round(self) -> Self;
@@ -923,14 +903,7 @@ impl FloatCore for f64 {
Self::fract(self) -> Self;
Self::abs(self) -> Self;
Self::signum(self) -> Self;
Self::is_sign_positive(self) -> bool;
Self::is_sign_negative(self) -> bool;
Self::min(self, other: Self) -> Self;
Self::max(self, other: Self) -> Self;
Self::recip(self) -> Self;
Self::powi(self, n: i32) -> Self;
Self::to_degrees(self) -> Self;
Self::to_radians(self) -> Self;
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -940,8 +913,6 @@ impl FloatCore for f64 {
libm::round as round(self) -> Self;
libm::trunc as trunc(self) -> Self;
libm::fabs as abs(self) -> Self;
libm::fmin as min(self, other: Self) -> Self;
libm::fmax as max(self, other: Self) -> Self;
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -1138,9 +1109,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// // Values between `0` and `min` are Subnormal.
/// assert!(!lower_than_min.is_normal());
/// ```
/// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
/// [subnormal]: http://en.wikipedia.org/wiki/Subnormal_number
fn is_normal(self) -> bool;
/// Returns `true` if the number is [subnormal].
///
/// ```
/// use num_traits::Float;
/// use std::f64;
///
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
/// let max = f64::MAX;
/// let lower_than_min = 1.0e-308_f64;
/// let zero = 0.0_f64;
///
/// assert!(!min.is_subnormal());
/// assert!(!max.is_subnormal());
///
/// assert!(!zero.is_subnormal());
/// assert!(!f64::NAN.is_subnormal());
/// assert!(!f64::INFINITY.is_subnormal());
/// // Values between `0` and `min` are Subnormal.
/// assert!(lower_than_min.is_subnormal());
/// ```
/// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
#[inline]
fn is_subnormal(self) -> bool {
self.classify() == FpCategory::Subnormal
}
/// Returns the floating point category of the number. If only one property
/// is going to be tested, it is generally faster to use the specific
/// predicate instead.
@@ -1266,12 +1263,13 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
fn signum(self) -> Self;
/// Returns `true` if `self` is positive, including `+0.0`,
/// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`.
/// `Float::infinity()`, and `Float::nan()`.
///
/// ```
/// use num_traits::Float;
/// use std::f64;
///
/// let nan: f64 = f64::NAN;
/// let neg_nan: f64 = -f64::NAN;
///
/// let f = 7.0;
@@ -1279,18 +1277,20 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
///
/// assert!(f.is_sign_positive());
/// assert!(!g.is_sign_positive());
/// assert!(nan.is_sign_positive());
/// assert!(!neg_nan.is_sign_positive());
/// ```
fn is_sign_positive(self) -> bool;
/// Returns `true` if `self` is negative, including `-0.0`,
/// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`.
/// `Float::neg_infinity()`, and `-Float::nan()`.
///
/// ```
/// use num_traits::Float;
/// use std::f64;
///
/// let nan: f64 = f64::NAN;
/// let neg_nan: f64 = -f64::NAN;
///
/// let f = 7.0;
/// let g = -7.0;
@@ -1298,6 +1298,7 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
/// assert!(!nan.is_sign_negative());
/// assert!(neg_nan.is_sign_negative());
/// ```
fn is_sign_negative(self) -> bool;
@@ -1528,6 +1529,23 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// ```
fn min(self, other: Self) -> Self;
/// Clamps a value between a min and max.
///
/// **Panics** in debug mode if `!(min <= max)`.
///
/// ```
/// use num_traits::Float;
///
/// let x = 1.0;
/// let y = 2.0;
/// let z = 3.0;
///
/// assert_eq!(x.clamp(y, z), 2.0);
/// ```
fn clamp(self, min: Self, max: Self) -> Self {
crate::clamp(self, min, max)
}
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
@@ -1924,7 +1942,9 @@ macro_rules! float_impl_std {
Self::is_infinite(self) -> bool;
Self::is_finite(self) -> bool;
Self::is_normal(self) -> bool;
Self::is_subnormal(self) -> bool;
Self::classify(self) -> FpCategory;
Self::clamp(self, min: Self, max: Self) -> Self;
Self::floor(self) -> Self;
Self::ceil(self) -> Self;
Self::round(self) -> Self;
@@ -1967,12 +1987,7 @@ macro_rules! float_impl_std {
Self::asinh(self) -> Self;
Self::acosh(self) -> Self;
Self::atanh(self) -> Self;
}
#[cfg(has_copysign)]
#[inline]
fn copysign(self, sign: Self) -> Self {
Self::copysign(self, sign)
Self::copysign(self, sign: Self) -> Self;
}
}
};
@@ -2008,26 +2023,31 @@ macro_rules! float_impl_libm {
}
forward! {
FloatCore::is_nan(self) -> bool;
FloatCore::is_infinite(self) -> bool;
FloatCore::is_finite(self) -> bool;
FloatCore::is_normal(self) -> bool;
FloatCore::classify(self) -> FpCategory;
Self::is_nan(self) -> bool;
Self::is_infinite(self) -> bool;
Self::is_finite(self) -> bool;
Self::is_normal(self) -> bool;
Self::is_subnormal(self) -> bool;
Self::clamp(self, min: Self, max: Self) -> Self;
Self::classify(self) -> FpCategory;
Self::is_sign_positive(self) -> bool;
Self::is_sign_negative(self) -> bool;
Self::min(self, other: Self) -> Self;
Self::max(self, other: Self) -> Self;
Self::recip(self) -> Self;
Self::to_degrees(self) -> Self;
Self::to_radians(self) -> Self;
}
forward! {
FloatCore::signum(self) -> Self;
FloatCore::is_sign_positive(self) -> bool;
FloatCore::is_sign_negative(self) -> bool;
FloatCore::recip(self) -> Self;
FloatCore::powi(self, n: i32) -> Self;
FloatCore::to_degrees(self) -> Self;
FloatCore::to_radians(self) -> Self;
}
};
}
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
// Safety: this identical to the implementation of f32::to_bits(),
// which is only available starting at Rust 1.20
let bits: u32 = unsafe { mem::transmute(f) };
let bits: u32 = f.to_bits();
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
let mantissa = if exponent == 0 {
@@ -2041,9 +2061,7 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
}
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
// Safety: this identical to the implementation of f64::to_bits(),
// which is only available starting at Rust 1.20
let bits: u64 = unsafe { mem::transmute(f) };
let bits: u64 = f.to_bits();
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
let mantissa = if exponent == 0 {
@@ -2103,8 +2121,6 @@ impl Float for f32 {
libm::asinhf as asinh(self) -> Self;
libm::acoshf as acosh(self) -> Self;
libm::atanhf as atanh(self) -> Self;
libm::fmaxf as max(self, other: Self) -> Self;
libm::fminf as min(self, other: Self) -> Self;
libm::copysignf as copysign(self, other: Self) -> Self;
}
}
@@ -2151,8 +2167,6 @@ impl Float for f64 {
libm::asinh as asinh(self) -> Self;
libm::acosh as acosh(self) -> Self;
libm::atanh as atanh(self) -> Self;
libm::fmax as max(self, other: Self) -> Self;
libm::fmin as min(self, other: Self) -> Self;
libm::copysign as copysign(self, sign: Self) -> Self;
}
}
@@ -2228,6 +2242,89 @@ float_const_impl! {
SQRT_2,
}
/// Trait for floating point numbers that provide an implementation
/// of the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
/// floating point standard.
pub trait TotalOrder {
/// Return the ordering between `self` and `other`.
///
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
/// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
/// floating point standard. The values are ordered in the following sequence:
///
/// - negative quiet NaN
/// - negative signaling NaN
/// - negative infinity
/// - negative numbers
/// - negative subnormal numbers
/// - negative zero
/// - positive zero
/// - positive subnormal numbers
/// - positive numbers
/// - positive infinity
/// - positive signaling NaN
/// - positive quiet NaN.
///
/// The ordering established by this function does not always agree with the
/// [`PartialOrd`] and [`PartialEq`] implementations. For example,
/// they consider negative and positive zero equal, while `total_cmp`
/// doesn't.
///
/// The interpretation of the signaling NaN bit follows the definition in
/// the IEEE 754 standard, which may not match the interpretation by some of
/// the older, non-conformant (e.g. MIPS) hardware implementations.
///
/// # Examples
/// ```
/// use num_traits::float::TotalOrder;
/// use std::cmp::Ordering;
/// use std::{f32, f64};
///
/// fn check_eq<T: TotalOrder>(x: T, y: T) {
/// assert_eq!(x.total_cmp(&y), Ordering::Equal);
/// }
///
/// check_eq(f64::NAN, f64::NAN);
/// check_eq(f32::NAN, f32::NAN);
///
/// fn check_lt<T: TotalOrder>(x: T, y: T) {
/// assert_eq!(x.total_cmp(&y), Ordering::Less);
/// }
///
/// check_lt(-f64::NAN, f64::NAN);
/// check_lt(f64::INFINITY, f64::NAN);
/// check_lt(-0.0_f64, 0.0_f64);
/// ```
fn total_cmp(&self, other: &Self) -> Ordering;
}
macro_rules! totalorder_impl {
($T:ident, $I:ident, $U:ident, $bits:expr) => {
impl TotalOrder for $T {
#[inline]
#[cfg(has_total_cmp)]
fn total_cmp(&self, other: &Self) -> Ordering {
// Forward to the core implementation
Self::total_cmp(&self, other)
}
#[inline]
#[cfg(not(has_total_cmp))]
fn total_cmp(&self, other: &Self) -> Ordering {
// Backport the core implementation (since 1.62)
let mut left = self.to_bits() as $I;
let mut right = other.to_bits() as $I;
left ^= (((left >> ($bits - 1)) as $U) >> 1) as $I;
right ^= (((right >> ($bits - 1)) as $U) >> 1) as $I;
left.cmp(&right)
}
}
};
}
totalorder_impl!(f64, i64, u64, 64);
totalorder_impl!(f32, i32, u32, 32);
#[cfg(test)]
mod tests {
use core::f64::consts;
@@ -2244,7 +2341,7 @@ mod tests {
#[test]
fn convert_deg_rad() {
use float::FloatCore;
use crate::float::FloatCore;
for &(deg, rad) in &DEG_RAD_PAIRS {
assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6);
@@ -2260,7 +2357,7 @@ mod tests {
#[test]
fn convert_deg_rad_std() {
for &(deg, rad) in &DEG_RAD_PAIRS {
use Float;
use crate::Float;
assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
@@ -2272,11 +2369,8 @@ mod tests {
}
#[test]
// This fails with the forwarded `std` implementation in Rust 1.8.
// To avoid the failure, the test is limited to `no_std` builds.
#[cfg(not(feature = "std"))]
fn to_degrees_rounding() {
use float::FloatCore;
use crate::float::FloatCore;
assert_eq!(
FloatCore::to_degrees(1_f32),
@@ -2287,7 +2381,7 @@ mod tests {
#[test]
#[cfg(any(feature = "std", feature = "libm"))]
fn extra_logs() {
use float::{Float, FloatConst};
use crate::float::{Float, FloatConst};
fn check<F: Float + FloatConst>(diff: F) {
let _2 = F::from(2.0).unwrap();
@@ -2306,7 +2400,7 @@ mod tests {
#[test]
#[cfg(any(feature = "std", feature = "libm"))]
fn copysign() {
use float::Float;
use crate::float::Float;
test_copysign_generic(2.0_f32, -2.0_f32, f32::nan());
test_copysign_generic(2.0_f64, -2.0_f64, f64::nan());
test_copysignf(2.0_f32, -2.0_f32, f32::nan());
@@ -2314,8 +2408,8 @@ mod tests {
#[cfg(any(feature = "std", feature = "libm"))]
fn test_copysignf(p: f32, n: f32, nan: f32) {
use crate::float::Float;
use core::ops::Neg;
use float::Float;
assert!(p.is_sign_positive());
assert!(n.is_sign_negative());
@@ -2327,16 +2421,16 @@ mod tests {
assert_eq!(n, Float::copysign(n, n));
assert_eq!(n.neg(), Float::copysign(n, p));
// FIXME: is_sign... only works on NaN starting in Rust 1.20
// assert!(Float::copysign(nan, p).is_sign_positive());
// assert!(Float::copysign(nan, n).is_sign_negative());
assert!(Float::copysign(nan, p).is_sign_positive());
assert!(Float::copysign(nan, n).is_sign_negative());
}
#[cfg(any(feature = "std", feature = "libm"))]
fn test_copysign_generic<F: ::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
fn test_copysign_generic<F: crate::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
assert!(p.is_sign_positive());
assert!(n.is_sign_negative());
assert!(nan.is_nan());
assert!(!nan.is_subnormal());
assert_eq!(p, p.copysign(p));
assert_eq!(p.neg(), p.copysign(n));
@@ -2344,8 +2438,76 @@ mod tests {
assert_eq!(n, n.copysign(n));
assert_eq!(n.neg(), n.copysign(p));
// FIXME: is_sign... only works on NaN starting in Rust 1.20
// assert!(nan.copysign(p).is_sign_positive());
// assert!(nan.copysign(n).is_sign_negative());
assert!(nan.copysign(p).is_sign_positive());
assert!(nan.copysign(n).is_sign_negative());
}
#[cfg(any(feature = "std", feature = "libm"))]
fn test_subnormal<F: crate::float::Float + ::core::fmt::Debug>() {
let min_positive = F::min_positive_value();
let lower_than_min = min_positive / F::from(2.0f32).unwrap();
assert!(!min_positive.is_subnormal());
assert!(lower_than_min.is_subnormal());
}
#[test]
#[cfg(any(feature = "std", feature = "libm"))]
fn subnormal() {
test_subnormal::<f64>();
test_subnormal::<f32>();
}
#[test]
fn total_cmp() {
use crate::float::TotalOrder;
use core::cmp::Ordering;
use core::{f32, f64};
fn check_eq<T: TotalOrder>(x: T, y: T) {
assert_eq!(x.total_cmp(&y), Ordering::Equal);
}
fn check_lt<T: TotalOrder>(x: T, y: T) {
assert_eq!(x.total_cmp(&y), Ordering::Less);
}
fn check_gt<T: TotalOrder>(x: T, y: T) {
assert_eq!(x.total_cmp(&y), Ordering::Greater);
}
check_eq(f64::NAN, f64::NAN);
check_eq(f32::NAN, f32::NAN);
check_lt(-0.0_f64, 0.0_f64);
check_lt(-0.0_f32, 0.0_f32);
// x87 registers don't preserve the exact value of signaling NaN:
// https://github.com/rust-lang/rust/issues/115567
#[cfg(not(target_arch = "x86"))]
{
let s_nan = f64::from_bits(0x7ff4000000000000);
let q_nan = f64::from_bits(0x7ff8000000000000);
check_lt(s_nan, q_nan);
let neg_s_nan = f64::from_bits(0xfff4000000000000);
let neg_q_nan = f64::from_bits(0xfff8000000000000);
check_lt(neg_q_nan, neg_s_nan);
let s_nan = f32::from_bits(0x7fa00000);
let q_nan = f32::from_bits(0x7fc00000);
check_lt(s_nan, q_nan);
let neg_s_nan = f32::from_bits(0xffa00000);
let neg_q_nan = f32::from_bits(0xffc00000);
check_lt(neg_q_nan, neg_s_nan);
}
check_lt(-f64::NAN, f64::NEG_INFINITY);
check_gt(1.0_f64, -f64::NAN);
check_lt(f64::INFINITY, f64::NAN);
check_gt(f64::NAN, 1.0_f64);
check_lt(-f32::NAN, f32::NEG_INFINITY);
check_gt(1.0_f32, -f32::NAN);
check_lt(f32::INFINITY, f32::NAN);
check_gt(f32::NAN, 1.0_f32);
}
}

View File

@@ -5,7 +5,7 @@ use core::ops::{Add, Mul};
///
/// # Laws
///
/// ```{.text}
/// ```text
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ```
@@ -28,6 +28,13 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
fn is_zero(&self) -> bool;
}
/// Defines an associated constant representing the additive identity element
/// for `Self`.
pub trait ConstZero: Zero {
/// The additive identity element of `Self`, `0`.
const ZERO: Self;
}
macro_rules! zero_impl {
($t:ty, $v:expr) => {
impl Zero for $t {
@@ -40,6 +47,10 @@ macro_rules! zero_impl {
*self == $v
}
}
impl ConstZero for $t {
const ZERO: Self = $v;
}
};
}
@@ -48,7 +59,6 @@ zero_impl!(u8, 0);
zero_impl!(u16, 0);
zero_impl!(u32, 0);
zero_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(u128, 0);
zero_impl!(isize, 0);
@@ -56,7 +66,6 @@ zero_impl!(i8, 0);
zero_impl!(i16, 0);
zero_impl!(i32, 0);
zero_impl!(i64, 0);
#[cfg(has_i128)]
zero_impl!(i128, 0);
zero_impl!(f32, 0.0);
@@ -79,11 +88,18 @@ where
}
}
impl<T: ConstZero> ConstZero for Wrapping<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>,
{
const ZERO: Self = Wrapping(T::ZERO);
}
/// Defines a multiplicative identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// ```text
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ```
@@ -117,6 +133,13 @@ pub trait One: Sized + Mul<Self, Output = Self> {
}
}
/// Defines an associated constant representing the multiplicative identity
/// element for `Self`.
pub trait ConstOne: One {
/// The multiplicative identity element of `Self`, `1`.
const ONE: Self;
}
macro_rules! one_impl {
($t:ty, $v:expr) => {
impl One for $t {
@@ -129,6 +152,10 @@ macro_rules! one_impl {
*self == $v
}
}
impl ConstOne for $t {
const ONE: Self = $v;
}
};
}
@@ -137,7 +164,6 @@ one_impl!(u8, 1);
one_impl!(u16, 1);
one_impl!(u32, 1);
one_impl!(u64, 1);
#[cfg(has_i128)]
one_impl!(u128, 1);
one_impl!(isize, 1);
@@ -145,7 +171,6 @@ 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);
@@ -164,6 +189,13 @@ where
}
}
impl<T: ConstOne> ConstOne for Wrapping<T>
where
Wrapping<T>: Mul<Output = Wrapping<T>>,
{
const ONE: Self = Wrapping(T::ONE);
}
// Some helper functions provided for backwards compatibility.
/// Returns the additive identity, `0`.

View File

@@ -1,9 +1,9 @@
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use bounds::Bounded;
use ops::checked::*;
use ops::saturating::Saturating;
use {Num, NumCast};
use crate::bounds::Bounded;
use crate::ops::checked::*;
use crate::ops::saturating::Saturating;
use crate::{Num, NumCast};
/// Generic trait for primitive integers.
///
@@ -404,7 +404,6 @@ macro_rules! prim_int_impl {
<$T>::count_zeros(self)
}
#[cfg(has_leading_trailing_ones)]
#[inline]
fn leading_ones(self) -> u32 {
<$T>::leading_ones(self)
@@ -415,7 +414,6 @@ macro_rules! prim_int_impl {
<$T>::leading_zeros(self)
}
#[cfg(has_leading_trailing_ones)]
#[inline]
fn trailing_ones(self) -> u32 {
<$T>::trailing_ones(self)
@@ -461,7 +459,6 @@ macro_rules! prim_int_impl {
<$T>::swap_bytes(self)
}
#[cfg(has_reverse_bits)]
#[inline]
fn reverse_bits(self) -> Self {
<$T>::reverse_bits(self)
@@ -500,20 +497,18 @@ prim_int_impl!(u8, i8, u8);
prim_int_impl!(u16, i16, u16);
prim_int_impl!(u32, i32, u32);
prim_int_impl!(u64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(u128, i128, u128);
prim_int_impl!(usize, isize, usize);
prim_int_impl!(i8, i8, u8);
prim_int_impl!(i16, i16, u16);
prim_int_impl!(i32, i32, u32);
prim_int_impl!(i64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(i128, i128, u128);
prim_int_impl!(isize, isize, usize);
#[cfg(test)]
mod tests {
use int::PrimInt;
use crate::int::PrimInt;
#[test]
pub fn reverse_bits() {
@@ -554,7 +549,6 @@ mod tests {
}
#[test]
#[cfg(has_i128)]
pub fn reverse_bits_i128() {
use core::i128;

View File

@@ -12,43 +12,42 @@
//!
//! ## Compatibility
//!
//! The `num-traits` crate is tested for rustc 1.8 and greater.
//! The `num-traits` crate is tested for rustc 1.60 and greater.
#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
#![deny(unconditional_recursion)]
#![no_std]
// Need to explicitly bring the crate in for inherent float methods
#[cfg(feature = "std")]
extern crate std;
// Only `no_std` builds actually use `libm`.
#[cfg(all(not(feature = "std"), feature = "libm"))]
extern crate libm;
use core::fmt;
use core::num::Wrapping;
use core::ops::{Add, Div, Mul, Rem, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
pub use bounds::Bounded;
pub use crate::bounds::Bounded;
#[cfg(any(feature = "std", feature = "libm"))]
pub use float::Float;
pub use float::FloatConst;
pub use crate::float::Float;
pub use crate::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};
pub use int::PrimInt;
pub use ops::checked::{
pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
pub use crate::identities::{one, zero, ConstOne, ConstZero, One, Zero};
pub use crate::int::PrimInt;
pub use crate::ops::bytes::{FromBytes, ToBytes};
pub use crate::ops::checked::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
};
pub use ops::euclid::{CheckedEuclid, Euclid};
pub use ops::inv::Inv;
pub use ops::mul_add::{MulAdd, MulAddAssign};
pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
pub use ops::wrapping::{
pub use crate::ops::euclid::{CheckedEuclid, Euclid};
pub use crate::ops::inv::Inv;
pub use crate::ops::mul_add::{MulAdd, MulAddAssign};
pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
pub use crate::ops::wrapping::{
WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
};
pub use pow::{checked_pow, pow, Pow};
pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
pub use crate::pow::{checked_pow, pow, Pow};
pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned};
#[macro_use]
mod macros;
@@ -172,9 +171,8 @@ macro_rules! int_trait_impl {
}
)*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
#[cfg(has_i128)]
int_trait_impl!(Num for u128 i128);
int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
impl<T: Num> Num for Wrapping<T>
where
@@ -199,7 +197,7 @@ pub struct ParseFloatError {
}
impl fmt::Display for ParseFloatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let description = match self.kind {
FloatErrorKind::Empty => "cannot parse float from empty string",
FloatErrorKind::Invalid => "invalid float literal",
@@ -255,11 +253,7 @@ macro_rules! float_trait_impl {
fn slice_shift_char(src: &str) -> Option<(char, &str)> {
let mut chars = src.chars();
if let Some(ch) = chars.next() {
Some((ch, chars.as_str()))
} else {
None
}
Some((chars.next()?, chars.as_str()))
}
let (is_positive, src) = match slice_shift_char(src) {
@@ -282,13 +276,13 @@ macro_rules! float_trait_impl {
match c.to_digit(radix) {
Some(digit) => {
// shift significand one digit left
sig = sig * (radix as $t);
sig *= radix as $t;
// add/subtract current digit depending on sign
if is_positive {
sig = sig + ((digit as isize) as $t);
sig += (digit as isize) as $t;
} else {
sig = sig - ((digit as isize) as $t);
sig -= (digit as isize) as $t;
}
// Detect overflow by comparing to last value, except
@@ -330,7 +324,7 @@ macro_rules! float_trait_impl {
match c.to_digit(radix) {
Some(digit) => {
// Decrease power one order of magnitude
power = power / (radix as $t);
power /= radix as $t;
// add/subtract current digit depending on sign
sig = if is_positive {
sig + (digit as $t) * power
@@ -424,6 +418,7 @@ pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
///
/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
#[inline]
#[allow(clippy::eq_op)]
pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
debug_assert!(min == min, "min must not be NAN");
if input < min {
@@ -441,6 +436,7 @@ pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
///
/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
#[inline]
#[allow(clippy::eq_op)]
pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
debug_assert!(max == max, "max must not be NAN");
if input > max {
@@ -625,7 +621,6 @@ fn check_numassign_ops() {
assert_eq!(compute(1, 2), 1)
}
#[cfg(has_int_assignop_ref)]
#[test]
fn check_numassignref_ops() {
fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {

View File

@@ -0,0 +1,317 @@
use core::borrow::{Borrow, BorrowMut};
use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
use core::fmt::Debug;
use core::hash::Hash;
pub trait NumBytes:
Debug
+ AsRef<[u8]>
+ AsMut<[u8]>
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ Hash
+ Borrow<[u8]>
+ BorrowMut<[u8]>
{
}
impl<T> NumBytes for T where
T: Debug
+ AsRef<[u8]>
+ AsMut<[u8]>
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ Hash
+ Borrow<[u8]>
+ BorrowMut<[u8]>
+ ?Sized
{
}
pub trait ToBytes {
type Bytes: NumBytes;
/// Return the memory representation of this number as a byte array in big-endian byte order.
///
/// # Examples
///
/// ```
/// use num_traits::ToBytes;
///
/// let bytes = ToBytes::to_be_bytes(&0x12345678u32);
/// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
/// ```
fn to_be_bytes(&self) -> Self::Bytes;
/// Return the memory representation of this number as a byte array in little-endian byte order.
///
/// # Examples
///
/// ```
/// use num_traits::ToBytes;
///
/// let bytes = ToBytes::to_le_bytes(&0x12345678u32);
/// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
/// ```
fn to_le_bytes(&self) -> Self::Bytes;
/// Return the memory representation of this number as a byte array in native byte order.
///
/// As the target platform's native endianness is used,
/// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
///
/// [`to_be_bytes`]: #method.to_be_bytes
/// [`to_le_bytes`]: #method.to_le_bytes
///
/// # Examples
///
/// ```
/// use num_traits::ToBytes;
///
/// #[cfg(target_endian = "big")]
/// let expected = [0x12, 0x34, 0x56, 0x78];
///
/// #[cfg(target_endian = "little")]
/// let expected = [0x78, 0x56, 0x34, 0x12];
///
/// let bytes = ToBytes::to_ne_bytes(&0x12345678u32);
/// assert_eq!(bytes, expected)
/// ```
fn to_ne_bytes(&self) -> Self::Bytes {
#[cfg(target_endian = "big")]
let bytes = self.to_be_bytes();
#[cfg(target_endian = "little")]
let bytes = self.to_le_bytes();
bytes
}
}
pub trait FromBytes: Sized {
type Bytes: NumBytes + ?Sized;
/// Create a number from its representation as a byte array in big endian.
///
/// # Examples
///
/// ```
/// use num_traits::FromBytes;
///
/// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]);
/// assert_eq!(value, 0x12345678);
/// ```
fn from_be_bytes(bytes: &Self::Bytes) -> Self;
/// Create a number from its representation as a byte array in little endian.
///
/// # Examples
///
/// ```
/// use num_traits::FromBytes;
///
/// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]);
/// assert_eq!(value, 0x12345678);
/// ```
fn from_le_bytes(bytes: &Self::Bytes) -> Self;
/// Create a number from its memory representation as a byte array in native endianness.
///
/// As the target platform's native endianness is used,
/// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead.
///
/// [`from_be_bytes`]: #method.from_be_bytes
/// [`from_le_bytes`]: #method.from_le_bytes
///
/// # Examples
///
/// ```
/// use num_traits::FromBytes;
///
/// #[cfg(target_endian = "big")]
/// let bytes = [0x12, 0x34, 0x56, 0x78];
///
/// #[cfg(target_endian = "little")]
/// let bytes = [0x78, 0x56, 0x34, 0x12];
///
/// let value: u32 = FromBytes::from_ne_bytes(&bytes);
/// assert_eq!(value, 0x12345678)
/// ```
fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
#[cfg(target_endian = "big")]
let this = Self::from_be_bytes(bytes);
#[cfg(target_endian = "little")]
let this = Self::from_le_bytes(bytes);
this
}
}
macro_rules! float_to_from_bytes_impl {
($T:ty, $L:expr) => {
impl ToBytes for $T {
type Bytes = [u8; $L];
#[inline]
fn to_be_bytes(&self) -> Self::Bytes {
<$T>::to_be_bytes(*self)
}
#[inline]
fn to_le_bytes(&self) -> Self::Bytes {
<$T>::to_le_bytes(*self)
}
#[inline]
fn to_ne_bytes(&self) -> Self::Bytes {
<$T>::to_ne_bytes(*self)
}
}
impl FromBytes for $T {
type Bytes = [u8; $L];
#[inline]
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_be_bytes(*bytes)
}
#[inline]
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_le_bytes(*bytes)
}
#[inline]
fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_ne_bytes(*bytes)
}
}
};
}
macro_rules! int_to_from_bytes_impl {
($T:ty, $L:expr) => {
impl ToBytes for $T {
type Bytes = [u8; $L];
#[inline]
fn to_be_bytes(&self) -> Self::Bytes {
<$T>::to_be_bytes(*self)
}
#[inline]
fn to_le_bytes(&self) -> Self::Bytes {
<$T>::to_le_bytes(*self)
}
#[inline]
fn to_ne_bytes(&self) -> Self::Bytes {
<$T>::to_ne_bytes(*self)
}
}
impl FromBytes for $T {
type Bytes = [u8; $L];
#[inline]
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_be_bytes(*bytes)
}
#[inline]
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_le_bytes(*bytes)
}
#[inline]
fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
<$T>::from_ne_bytes(*bytes)
}
}
};
}
int_to_from_bytes_impl!(u8, 1);
int_to_from_bytes_impl!(u16, 2);
int_to_from_bytes_impl!(u32, 4);
int_to_from_bytes_impl!(u64, 8);
int_to_from_bytes_impl!(u128, 16);
#[cfg(target_pointer_width = "64")]
int_to_from_bytes_impl!(usize, 8);
#[cfg(target_pointer_width = "32")]
int_to_from_bytes_impl!(usize, 4);
int_to_from_bytes_impl!(i8, 1);
int_to_from_bytes_impl!(i16, 2);
int_to_from_bytes_impl!(i32, 4);
int_to_from_bytes_impl!(i64, 8);
int_to_from_bytes_impl!(i128, 16);
#[cfg(target_pointer_width = "64")]
int_to_from_bytes_impl!(isize, 8);
#[cfg(target_pointer_width = "32")]
int_to_from_bytes_impl!(isize, 4);
float_to_from_bytes_impl!(f32, 4);
float_to_from_bytes_impl!(f64, 8);
#[cfg(test)]
mod tests {
use super::*;
macro_rules! check_to_from_bytes {
($( $ty:ty )+) => {$({
let n = 1;
let be = <$ty as ToBytes>::to_be_bytes(&n);
let le = <$ty as ToBytes>::to_le_bytes(&n);
let ne = <$ty as ToBytes>::to_ne_bytes(&n);
assert_eq!(*be.last().unwrap(), 1);
assert_eq!(*le.first().unwrap(), 1);
if cfg!(target_endian = "big") {
assert_eq!(*ne.last().unwrap(), 1);
} else {
assert_eq!(*ne.first().unwrap(), 1);
}
assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
if cfg!(target_endian = "big") {
assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
} else {
assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
}
})+}
}
#[test]
fn convert_between_int_and_bytes() {
check_to_from_bytes!(u8 u16 u32 u64 u128 usize);
check_to_from_bytes!(i8 i16 i32 i64 i128 isize);
}
#[test]
fn convert_between_float_and_bytes() {
macro_rules! check_to_from_bytes {
($( $ty:ty )+) => {$(
let n: $ty = 3.14;
let be = <$ty as ToBytes>::to_be_bytes(&n);
let le = <$ty as ToBytes>::to_le_bytes(&n);
let ne = <$ty as ToBytes>::to_ne_bytes(&n);
assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
if cfg!(target_endian = "big") {
assert_eq!(ne, be);
assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
} else {
assert_eq!(ne, le);
assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
}
)+}
}
check_to_from_bytes!(f32 f64);
}
}

View File

@@ -24,7 +24,6 @@ checked_impl!(CheckedAdd, checked_add, u16);
checked_impl!(CheckedAdd, checked_add, u32);
checked_impl!(CheckedAdd, checked_add, u64);
checked_impl!(CheckedAdd, checked_add, usize);
#[cfg(has_i128)]
checked_impl!(CheckedAdd, checked_add, u128);
checked_impl!(CheckedAdd, checked_add, i8);
@@ -32,7 +31,6 @@ checked_impl!(CheckedAdd, checked_add, i16);
checked_impl!(CheckedAdd, checked_add, i32);
checked_impl!(CheckedAdd, checked_add, i64);
checked_impl!(CheckedAdd, checked_add, isize);
#[cfg(has_i128)]
checked_impl!(CheckedAdd, checked_add, i128);
/// Performs subtraction that returns `None` instead of wrapping around on underflow.
@@ -47,7 +45,6 @@ checked_impl!(CheckedSub, checked_sub, u16);
checked_impl!(CheckedSub, checked_sub, u32);
checked_impl!(CheckedSub, checked_sub, u64);
checked_impl!(CheckedSub, checked_sub, usize);
#[cfg(has_i128)]
checked_impl!(CheckedSub, checked_sub, u128);
checked_impl!(CheckedSub, checked_sub, i8);
@@ -55,7 +52,6 @@ checked_impl!(CheckedSub, checked_sub, i16);
checked_impl!(CheckedSub, checked_sub, i32);
checked_impl!(CheckedSub, checked_sub, i64);
checked_impl!(CheckedSub, checked_sub, isize);
#[cfg(has_i128)]
checked_impl!(CheckedSub, checked_sub, i128);
/// Performs multiplication that returns `None` instead of wrapping around on underflow or
@@ -71,7 +67,6 @@ checked_impl!(CheckedMul, checked_mul, u16);
checked_impl!(CheckedMul, checked_mul, u32);
checked_impl!(CheckedMul, checked_mul, u64);
checked_impl!(CheckedMul, checked_mul, usize);
#[cfg(has_i128)]
checked_impl!(CheckedMul, checked_mul, u128);
checked_impl!(CheckedMul, checked_mul, i8);
@@ -79,7 +74,6 @@ checked_impl!(CheckedMul, checked_mul, i16);
checked_impl!(CheckedMul, checked_mul, i32);
checked_impl!(CheckedMul, checked_mul, i64);
checked_impl!(CheckedMul, checked_mul, isize);
#[cfg(has_i128)]
checked_impl!(CheckedMul, checked_mul, i128);
/// Performs division that returns `None` instead of panicking on division by zero and instead of
@@ -95,7 +89,6 @@ checked_impl!(CheckedDiv, checked_div, u16);
checked_impl!(CheckedDiv, checked_div, u32);
checked_impl!(CheckedDiv, checked_div, u64);
checked_impl!(CheckedDiv, checked_div, usize);
#[cfg(has_i128)]
checked_impl!(CheckedDiv, checked_div, u128);
checked_impl!(CheckedDiv, checked_div, i8);
@@ -103,7 +96,6 @@ checked_impl!(CheckedDiv, checked_div, i16);
checked_impl!(CheckedDiv, checked_div, i32);
checked_impl!(CheckedDiv, checked_div, i64);
checked_impl!(CheckedDiv, checked_div, isize);
#[cfg(has_i128)]
checked_impl!(CheckedDiv, checked_div, i128);
/// Performs an integral remainder that returns `None` instead of panicking on division by zero and
@@ -136,7 +128,6 @@ checked_impl!(CheckedRem, checked_rem, u16);
checked_impl!(CheckedRem, checked_rem, u32);
checked_impl!(CheckedRem, checked_rem, u64);
checked_impl!(CheckedRem, checked_rem, usize);
#[cfg(has_i128)]
checked_impl!(CheckedRem, checked_rem, u128);
checked_impl!(CheckedRem, checked_rem, i8);
@@ -144,7 +135,6 @@ checked_impl!(CheckedRem, checked_rem, i16);
checked_impl!(CheckedRem, checked_rem, i32);
checked_impl!(CheckedRem, checked_rem, i64);
checked_impl!(CheckedRem, checked_rem, isize);
#[cfg(has_i128)]
checked_impl!(CheckedRem, checked_rem, i128);
macro_rules! checked_impl_unary {
@@ -184,7 +174,6 @@ checked_impl_unary!(CheckedNeg, checked_neg, u16);
checked_impl_unary!(CheckedNeg, checked_neg, u32);
checked_impl_unary!(CheckedNeg, checked_neg, u64);
checked_impl_unary!(CheckedNeg, checked_neg, usize);
#[cfg(has_i128)]
checked_impl_unary!(CheckedNeg, checked_neg, u128);
checked_impl_unary!(CheckedNeg, checked_neg, i8);
@@ -192,11 +181,10 @@ checked_impl_unary!(CheckedNeg, checked_neg, i16);
checked_impl_unary!(CheckedNeg, checked_neg, i32);
checked_impl_unary!(CheckedNeg, checked_neg, i64);
checked_impl_unary!(CheckedNeg, checked_neg, isize);
#[cfg(has_i128)]
checked_impl_unary!(CheckedNeg, checked_neg, i128);
/// Performs a left shift that returns `None` on shifts larger than
/// the type width.
/// or equal to the type width.
pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
/// Checked shift left. Computes `self << rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
@@ -230,7 +218,6 @@ checked_shift_impl!(CheckedShl, checked_shl, u16);
checked_shift_impl!(CheckedShl, checked_shl, u32);
checked_shift_impl!(CheckedShl, checked_shl, u64);
checked_shift_impl!(CheckedShl, checked_shl, usize);
#[cfg(has_i128)]
checked_shift_impl!(CheckedShl, checked_shl, u128);
checked_shift_impl!(CheckedShl, checked_shl, i8);
@@ -238,11 +225,10 @@ checked_shift_impl!(CheckedShl, checked_shl, i16);
checked_shift_impl!(CheckedShl, checked_shl, i32);
checked_shift_impl!(CheckedShl, checked_shl, i64);
checked_shift_impl!(CheckedShl, checked_shl, isize);
#[cfg(has_i128)]
checked_shift_impl!(CheckedShl, checked_shl, i128);
/// Performs a right shift that returns `None` on shifts larger than
/// the type width.
/// or equal to the type width.
pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
@@ -265,7 +251,6 @@ checked_shift_impl!(CheckedShr, checked_shr, u16);
checked_shift_impl!(CheckedShr, checked_shr, u32);
checked_shift_impl!(CheckedShr, checked_shr, u64);
checked_shift_impl!(CheckedShr, checked_shr, usize);
#[cfg(has_i128)]
checked_shift_impl!(CheckedShr, checked_shr, u128);
checked_shift_impl!(CheckedShr, checked_shr, i8);
@@ -273,5 +258,4 @@ checked_shift_impl!(CheckedShr, checked_shr, i16);
checked_shift_impl!(CheckedShr, checked_shr, i32);
checked_shift_impl!(CheckedShr, checked_shr, i64);
checked_shift_impl!(CheckedShr, checked_shr, isize);
#[cfg(has_i128)]
checked_shift_impl!(CheckedShr, checked_shr, i128);

View File

@@ -46,11 +46,31 @@ pub trait Euclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> {
/// assert_eq!(Euclid::rem_euclid(&-a, &-b), 1);
/// ```
fn rem_euclid(&self, v: &Self) -> Self;
/// Returns both the quotient and remainder from Euclidean division.
///
/// By default, it internally calls both `Euclid::div_euclid` and `Euclid::rem_euclid`,
/// but it can be overridden in order to implement some optimization.
///
/// # Examples
///
/// ```
/// # use num_traits::Euclid;
/// let x = 5u8;
/// let y = 3u8;
///
/// let div = Euclid::div_euclid(&x, &y);
/// let rem = Euclid::rem_euclid(&x, &y);
///
/// assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y));
/// ```
fn div_rem_euclid(&self, v: &Self) -> (Self, Self) {
(self.div_euclid(v), self.rem_euclid(v))
}
}
macro_rules! euclid_forward_impl {
($($t:ty)*) => {$(
#[cfg(has_div_euclid)]
impl Euclid for $t {
#[inline]
fn div_euclid(&self, v: &$t) -> Self {
@@ -65,72 +85,17 @@ macro_rules! euclid_forward_impl {
)*}
}
macro_rules! euclid_int_impl {
($($t:ty)*) => {$(
euclid_forward_impl!($t);
euclid_forward_impl!(isize i8 i16 i32 i64 i128);
euclid_forward_impl!(usize u8 u16 u32 u64 u128);
#[cfg(not(has_div_euclid))]
impl Euclid for $t {
#[inline]
fn div_euclid(&self, v: &$t) -> Self {
let q = self / v;
if self % v < 0 {
return if *v > 0 { q - 1 } else { q + 1 }
}
q
}
#[inline]
fn rem_euclid(&self, v: &$t) -> Self {
let r = self % v;
if r < 0 {
if *v < 0 {
r - v
} else {
r + v
}
} else {
r
}
}
}
)*}
}
macro_rules! euclid_uint_impl {
($($t:ty)*) => {$(
euclid_forward_impl!($t);
#[cfg(not(has_div_euclid))]
impl Euclid for $t {
#[inline]
fn div_euclid(&self, v: &$t) -> Self {
self / v
}
#[inline]
fn rem_euclid(&self, v: &$t) -> Self {
self % v
}
}
)*}
}
euclid_int_impl!(isize i8 i16 i32 i64);
euclid_uint_impl!(usize u8 u16 u32 u64);
#[cfg(has_i128)]
euclid_int_impl!(i128);
#[cfg(has_i128)]
euclid_uint_impl!(u128);
#[cfg(all(has_div_euclid, feature = "std"))]
#[cfg(feature = "std")]
euclid_forward_impl!(f32 f64);
#[cfg(not(all(has_div_euclid, feature = "std")))]
#[cfg(not(feature = "std"))]
impl Euclid for f32 {
#[inline]
fn div_euclid(&self, v: &f32) -> f32 {
let q = <f32 as ::float::FloatCore>::trunc(self / v);
let q = <f32 as crate::float::FloatCore>::trunc(self / v);
if self % v < 0.0 {
return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
}
@@ -141,18 +106,18 @@ impl Euclid for f32 {
fn rem_euclid(&self, v: &f32) -> f32 {
let r = self % v;
if r < 0.0 {
r + <f32 as ::float::FloatCore>::abs(*v)
r + <f32 as crate::float::FloatCore>::abs(*v)
} else {
r
}
}
}
#[cfg(not(all(has_div_euclid, feature = "std")))]
#[cfg(not(feature = "std"))]
impl Euclid for f64 {
#[inline]
fn div_euclid(&self, v: &f64) -> f64 {
let q = <f64 as ::float::FloatCore>::trunc(self / v);
let q = <f64 as crate::float::FloatCore>::trunc(self / v);
if self % v < 0.0 {
return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
}
@@ -163,7 +128,7 @@ impl Euclid for f64 {
fn rem_euclid(&self, v: &f64) -> f64 {
let r = self % v;
if r < 0.0 {
r + <f64 as ::float::FloatCore>::abs(*v)
r + <f64 as crate::float::FloatCore>::abs(*v)
} else {
r
}
@@ -178,11 +143,30 @@ pub trait CheckedEuclid: Euclid {
/// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and
/// division by zero. If any of that happens, `None` is returned.
fn checked_rem_euclid(&self, v: &Self) -> Option<Self>;
/// Returns both the quotient and remainder from checked Euclidean division.
///
/// By default, it internally calls both `CheckedEuclid::checked_div_euclid` and `CheckedEuclid::checked_rem_euclid`,
/// but it can be overridden in order to implement some optimization.
/// # Examples
///
/// ```
/// # use num_traits::CheckedEuclid;
/// let x = 5u8;
/// let y = 3u8;
///
/// let div = CheckedEuclid::checked_div_euclid(&x, &y);
/// let rem = CheckedEuclid::checked_rem_euclid(&x, &y);
///
/// assert_eq!(Some((div.unwrap(), rem.unwrap())), CheckedEuclid::checked_div_rem_euclid(&x, &y));
/// ```
fn checked_div_rem_euclid(&self, v: &Self) -> Option<(Self, Self)> {
Some((self.checked_div_euclid(v)?, self.checked_rem_euclid(v)?))
}
}
macro_rules! checked_euclid_forward_impl {
($($t:ty)*) => {$(
#[cfg(has_div_euclid)]
impl CheckedEuclid for $t {
#[inline]
fn checked_div_euclid(&self, v: &$t) -> Option<Self> {
@@ -197,66 +181,8 @@ macro_rules! checked_euclid_forward_impl {
)*}
}
macro_rules! checked_euclid_int_impl {
($($t:ty)*) => {$(
checked_euclid_forward_impl!($t);
#[cfg(not(has_div_euclid))]
impl CheckedEuclid for $t {
#[inline]
fn checked_div_euclid(&self, v: &$t) -> Option<$t> {
if *v == 0 || (*self == Self::min_value() && *v == -1) {
None
} else {
Some(Euclid::div_euclid(self, v))
}
}
#[inline]
fn checked_rem_euclid(&self, v: &$t) -> Option<$t> {
if *v == 0 || (*self == Self::min_value() && *v == -1) {
None
} else {
Some(Euclid::rem_euclid(self, v))
}
}
}
)*}
}
macro_rules! checked_euclid_uint_impl {
($($t:ty)*) => {$(
checked_euclid_forward_impl!($t);
#[cfg(not(has_div_euclid))]
impl CheckedEuclid for $t {
#[inline]
fn checked_div_euclid(&self, v: &$t) -> Option<$t> {
if *v == 0 {
None
} else {
Some(Euclid::div_euclid(self, v))
}
}
#[inline]
fn checked_rem_euclid(&self, v: &$t) -> Option<$t> {
if *v == 0 {
None
} else {
Some(Euclid::rem_euclid(self, v))
}
}
}
)*}
}
checked_euclid_int_impl!(isize i8 i16 i32 i64);
checked_euclid_uint_impl!(usize u8 u16 u32 u64);
#[cfg(has_i128)]
checked_euclid_int_impl!(i128);
#[cfg(has_i128)]
checked_euclid_uint_impl!(u128);
checked_euclid_forward_impl!(isize i8 i16 i32 i64 i128);
checked_euclid_forward_impl!(usize u8 u16 u32 u64 u128);
#[cfg(test)]
mod tests {
@@ -270,8 +196,11 @@ mod tests {
{
let x: $t = 10;
let y: $t = 3;
assert_eq!(Euclid::div_euclid(&x, &y), 3);
assert_eq!(Euclid::rem_euclid(&x, &y), 1);
let div = Euclid::div_euclid(&x, &y);
let rem = Euclid::rem_euclid(&x, &y);
assert_eq!(div, 3);
assert_eq!(rem, 1);
assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y));
}
)+
};
@@ -292,6 +221,7 @@ mod tests {
assert_eq!(Euclid::div_euclid(&-x, &y), 4);
assert_eq!(Euclid::rem_euclid(&x, &y), 1);
assert_eq!(Euclid::rem_euclid(&-x, &y), 2);
assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y));
let x: $t = $t::min_value() + 1;
let y: $t = -1;
assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value());
@@ -300,7 +230,7 @@ mod tests {
};
}
test_euclid!(isize i8 i16 i32 i64);
test_euclid!(isize i8 i16 i32 i64 i128);
}
#[test]
@@ -312,13 +242,14 @@ mod tests {
let x: $t = 12.1;
let y: $t = 3.2;
assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x
<= 46.4 * <$t as ::float::FloatCore>::epsilon());
<= 46.4 * <$t as crate::float::FloatCore>::epsilon());
assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x
<= 46.4 * <$t as ::float::FloatCore>::epsilon());
<= 46.4 * <$t as crate::float::FloatCore>::epsilon());
assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x
<= 46.4 * <$t as ::float::FloatCore>::epsilon());
<= 46.4 * <$t as crate::float::FloatCore>::epsilon());
assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x
<= 46.4 * <$t as ::float::FloatCore>::epsilon());
<= 46.4 * <$t as crate::float::FloatCore>::epsilon());
assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y));
}
)+
};
@@ -342,6 +273,6 @@ mod tests {
};
}
test_euclid_checked!(isize i8 i16 i32 i64);
test_euclid_checked!(isize i8 i16 i32 i64 i128);
}
}

View File

@@ -1,3 +1,4 @@
pub mod bytes;
pub mod checked;
pub mod euclid;
pub mod inv;

View File

@@ -24,13 +24,13 @@ pub trait MulAdd<A = Self, B = Self> {
/// The resulting type after applying the fused multiply-add.
type Output;
/// Performs the fused multiply-add operation.
/// Performs the fused multiply-add operation `(self * a) + b`
fn mul_add(self, a: A, b: B) -> Self::Output;
}
/// The fused multiply-add assignment operation.
/// The fused multiply-add assignment operation `*self = (*self * a) + b`
pub trait MulAddAssign<A = Self, B = Self> {
/// Performs the fused multiply-add operation.
/// Performs the fused multiply-add assignment operation `*self = (*self * a) + b`
fn mul_add_assign(&mut self, a: A, b: B);
}
@@ -40,7 +40,7 @@ impl MulAdd<f32, f32> for f32 {
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self::Output {
<Self as ::Float>::mul_add(self, a, b)
<Self as crate::Float>::mul_add(self, a, b)
}
}
@@ -50,7 +50,7 @@ impl MulAdd<f64, f64> for f64 {
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self::Output {
<Self as ::Float>::mul_add(self, a, b)
<Self as crate::Float>::mul_add(self, a, b)
}
}
@@ -67,15 +67,14 @@ macro_rules! mul_add_impl {
)*}
}
mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
mul_add_impl!(MulAdd for i128 u128);
mul_add_impl!(MulAdd for isize i8 i16 i32 i64 i128);
mul_add_impl!(MulAdd for usize u8 u16 u32 u64 u128);
#[cfg(any(feature = "std", feature = "libm"))]
impl MulAddAssign<f32, f32> for f32 {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = <Self as ::Float>::mul_add(*self, a, b)
*self = <Self as crate::Float>::mul_add(*self, a, b)
}
}
@@ -83,7 +82,7 @@ impl MulAddAssign<f32, f32> for f32 {
impl MulAddAssign<f64, f64> for f64 {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = <Self as ::Float>::mul_add(*self, a, b)
*self = <Self as crate::Float>::mul_add(*self, a, b)
}
}
@@ -98,9 +97,8 @@ macro_rules! mul_add_assign_impl {
)*}
}
mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
mul_add_assign_impl!(MulAddAssign for i128 u128);
mul_add_assign_impl!(MulAddAssign for isize i8 i16 i32 i64 i128);
mul_add_assign_impl!(MulAddAssign for usize u8 u16 u32 u64 u128);
#[cfg(test)]
mod tests {

View File

@@ -1,8 +1,6 @@
use core::ops::{Add, Mul, Sub};
#[cfg(has_i128)]
use core::{i128, u128};
use core::{i16, i32, i64, i8, isize};
use core::{u16, u32, u64, u8, usize};
use core::{i128, i16, i32, i64, i8, isize};
use core::{u128, u16, u32, u64, u8, usize};
macro_rules! overflowing_impl {
($trait_name:ident, $method:ident, $t:ty) => {
@@ -27,7 +25,6 @@ overflowing_impl!(OverflowingAdd, overflowing_add, u16);
overflowing_impl!(OverflowingAdd, overflowing_add, u32);
overflowing_impl!(OverflowingAdd, overflowing_add, u64);
overflowing_impl!(OverflowingAdd, overflowing_add, usize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingAdd, overflowing_add, u128);
overflowing_impl!(OverflowingAdd, overflowing_add, i8);
@@ -35,7 +32,6 @@ overflowing_impl!(OverflowingAdd, overflowing_add, i16);
overflowing_impl!(OverflowingAdd, overflowing_add, i32);
overflowing_impl!(OverflowingAdd, overflowing_add, i64);
overflowing_impl!(OverflowingAdd, overflowing_add, isize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingAdd, overflowing_add, i128);
/// Performs substraction with a flag for overflow.
@@ -50,7 +46,6 @@ overflowing_impl!(OverflowingSub, overflowing_sub, u16);
overflowing_impl!(OverflowingSub, overflowing_sub, u32);
overflowing_impl!(OverflowingSub, overflowing_sub, u64);
overflowing_impl!(OverflowingSub, overflowing_sub, usize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingSub, overflowing_sub, u128);
overflowing_impl!(OverflowingSub, overflowing_sub, i8);
@@ -58,7 +53,6 @@ overflowing_impl!(OverflowingSub, overflowing_sub, i16);
overflowing_impl!(OverflowingSub, overflowing_sub, i32);
overflowing_impl!(OverflowingSub, overflowing_sub, i64);
overflowing_impl!(OverflowingSub, overflowing_sub, isize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingSub, overflowing_sub, i128);
/// Performs multiplication with a flag for overflow.
@@ -73,7 +67,6 @@ overflowing_impl!(OverflowingMul, overflowing_mul, u16);
overflowing_impl!(OverflowingMul, overflowing_mul, u32);
overflowing_impl!(OverflowingMul, overflowing_mul, u64);
overflowing_impl!(OverflowingMul, overflowing_mul, usize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingMul, overflowing_mul, u128);
overflowing_impl!(OverflowingMul, overflowing_mul, i8);
@@ -81,7 +74,6 @@ overflowing_impl!(OverflowingMul, overflowing_mul, i16);
overflowing_impl!(OverflowingMul, overflowing_mul, i32);
overflowing_impl!(OverflowingMul, overflowing_mul, i64);
overflowing_impl!(OverflowingMul, overflowing_mul, isize);
#[cfg(has_i128)]
overflowing_impl!(OverflowingMul, overflowing_mul, i128);
#[test]

View File

@@ -28,9 +28,8 @@ macro_rules! deprecated_saturating_impl {
)*}
}
deprecated_saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
deprecated_saturating_impl!(Saturating for i128 u128);
deprecated_saturating_impl!(Saturating for isize i8 i16 i32 i64 i128);
deprecated_saturating_impl!(Saturating for usize u8 u16 u32 u64 u128);
macro_rules! saturating_impl {
($trait_name:ident, $method:ident, $t:ty) => {
@@ -55,7 +54,6 @@ saturating_impl!(SaturatingAdd, saturating_add, u16);
saturating_impl!(SaturatingAdd, saturating_add, u32);
saturating_impl!(SaturatingAdd, saturating_add, u64);
saturating_impl!(SaturatingAdd, saturating_add, usize);
#[cfg(has_i128)]
saturating_impl!(SaturatingAdd, saturating_add, u128);
saturating_impl!(SaturatingAdd, saturating_add, i8);
@@ -63,7 +61,6 @@ saturating_impl!(SaturatingAdd, saturating_add, i16);
saturating_impl!(SaturatingAdd, saturating_add, i32);
saturating_impl!(SaturatingAdd, saturating_add, i64);
saturating_impl!(SaturatingAdd, saturating_add, isize);
#[cfg(has_i128)]
saturating_impl!(SaturatingAdd, saturating_add, i128);
/// Performs subtraction that saturates at the numeric bounds instead of overflowing.
@@ -78,7 +75,6 @@ saturating_impl!(SaturatingSub, saturating_sub, u16);
saturating_impl!(SaturatingSub, saturating_sub, u32);
saturating_impl!(SaturatingSub, saturating_sub, u64);
saturating_impl!(SaturatingSub, saturating_sub, usize);
#[cfg(has_i128)]
saturating_impl!(SaturatingSub, saturating_sub, u128);
saturating_impl!(SaturatingSub, saturating_sub, i8);
@@ -86,7 +82,6 @@ saturating_impl!(SaturatingSub, saturating_sub, i16);
saturating_impl!(SaturatingSub, saturating_sub, i32);
saturating_impl!(SaturatingSub, saturating_sub, i64);
saturating_impl!(SaturatingSub, saturating_sub, isize);
#[cfg(has_i128)]
saturating_impl!(SaturatingSub, saturating_sub, i128);
/// Performs multiplication that saturates at the numeric bounds instead of overflowing.
@@ -101,7 +96,6 @@ saturating_impl!(SaturatingMul, saturating_mul, u16);
saturating_impl!(SaturatingMul, saturating_mul, u32);
saturating_impl!(SaturatingMul, saturating_mul, u64);
saturating_impl!(SaturatingMul, saturating_mul, usize);
#[cfg(has_i128)]
saturating_impl!(SaturatingMul, saturating_mul, u128);
saturating_impl!(SaturatingMul, saturating_mul, i8);
@@ -109,7 +103,6 @@ saturating_impl!(SaturatingMul, saturating_mul, i16);
saturating_impl!(SaturatingMul, saturating_mul, i32);
saturating_impl!(SaturatingMul, saturating_mul, i64);
saturating_impl!(SaturatingMul, saturating_mul, isize);
#[cfg(has_i128)]
saturating_impl!(SaturatingMul, saturating_mul, i128);
// TODO: add SaturatingNeg for signed integer primitives once the saturating_neg() API is stable.

View File

@@ -32,7 +32,6 @@ wrapping_impl!(WrappingAdd, wrapping_add, u16);
wrapping_impl!(WrappingAdd, wrapping_add, u32);
wrapping_impl!(WrappingAdd, wrapping_add, u64);
wrapping_impl!(WrappingAdd, wrapping_add, usize);
#[cfg(has_i128)]
wrapping_impl!(WrappingAdd, wrapping_add, u128);
wrapping_impl!(WrappingAdd, wrapping_add, i8);
@@ -40,7 +39,6 @@ wrapping_impl!(WrappingAdd, wrapping_add, i16);
wrapping_impl!(WrappingAdd, wrapping_add, i32);
wrapping_impl!(WrappingAdd, wrapping_add, i64);
wrapping_impl!(WrappingAdd, wrapping_add, isize);
#[cfg(has_i128)]
wrapping_impl!(WrappingAdd, wrapping_add, i128);
/// Performs subtraction that wraps around on overflow.
@@ -55,7 +53,6 @@ wrapping_impl!(WrappingSub, wrapping_sub, u16);
wrapping_impl!(WrappingSub, wrapping_sub, u32);
wrapping_impl!(WrappingSub, wrapping_sub, u64);
wrapping_impl!(WrappingSub, wrapping_sub, usize);
#[cfg(has_i128)]
wrapping_impl!(WrappingSub, wrapping_sub, u128);
wrapping_impl!(WrappingSub, wrapping_sub, i8);
@@ -63,7 +60,6 @@ wrapping_impl!(WrappingSub, wrapping_sub, i16);
wrapping_impl!(WrappingSub, wrapping_sub, i32);
wrapping_impl!(WrappingSub, wrapping_sub, i64);
wrapping_impl!(WrappingSub, wrapping_sub, isize);
#[cfg(has_i128)]
wrapping_impl!(WrappingSub, wrapping_sub, i128);
/// Performs multiplication that wraps around on overflow.
@@ -78,7 +74,6 @@ wrapping_impl!(WrappingMul, wrapping_mul, u16);
wrapping_impl!(WrappingMul, wrapping_mul, u32);
wrapping_impl!(WrappingMul, wrapping_mul, u64);
wrapping_impl!(WrappingMul, wrapping_mul, usize);
#[cfg(has_i128)]
wrapping_impl!(WrappingMul, wrapping_mul, u128);
wrapping_impl!(WrappingMul, wrapping_mul, i8);
@@ -86,7 +81,6 @@ wrapping_impl!(WrappingMul, wrapping_mul, i16);
wrapping_impl!(WrappingMul, wrapping_mul, i32);
wrapping_impl!(WrappingMul, wrapping_mul, i64);
wrapping_impl!(WrappingMul, wrapping_mul, isize);
#[cfg(has_i128)]
wrapping_impl!(WrappingMul, wrapping_mul, i128);
macro_rules! wrapping_unary_impl {
@@ -127,14 +121,12 @@ wrapping_unary_impl!(WrappingNeg, wrapping_neg, u16);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u32);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u64);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, usize);
#[cfg(has_i128)]
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u128);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i8);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i16);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i32);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i64);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, isize);
#[cfg(has_i128)]
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i128);
macro_rules! wrapping_shift_impl {
@@ -172,7 +164,6 @@ wrapping_shift_impl!(WrappingShl, wrapping_shl, u16);
wrapping_shift_impl!(WrappingShl, wrapping_shl, u32);
wrapping_shift_impl!(WrappingShl, wrapping_shl, u64);
wrapping_shift_impl!(WrappingShl, wrapping_shl, usize);
#[cfg(has_i128)]
wrapping_shift_impl!(WrappingShl, wrapping_shl, u128);
wrapping_shift_impl!(WrappingShl, wrapping_shl, i8);
@@ -180,7 +171,6 @@ wrapping_shift_impl!(WrappingShl, wrapping_shl, i16);
wrapping_shift_impl!(WrappingShl, wrapping_shl, i32);
wrapping_shift_impl!(WrappingShl, wrapping_shl, i64);
wrapping_shift_impl!(WrappingShl, wrapping_shl, isize);
#[cfg(has_i128)]
wrapping_shift_impl!(WrappingShl, wrapping_shl, i128);
/// Performs a right shift that does not panic.
@@ -207,7 +197,6 @@ wrapping_shift_impl!(WrappingShr, wrapping_shr, u16);
wrapping_shift_impl!(WrappingShr, wrapping_shr, u32);
wrapping_shift_impl!(WrappingShr, wrapping_shr, u64);
wrapping_shift_impl!(WrappingShr, wrapping_shr, usize);
#[cfg(has_i128)]
wrapping_shift_impl!(WrappingShr, wrapping_shr, u128);
wrapping_shift_impl!(WrappingShr, wrapping_shr, i8);
@@ -215,7 +204,6 @@ wrapping_shift_impl!(WrappingShr, wrapping_shr, i16);
wrapping_shift_impl!(WrappingShr, wrapping_shr, i32);
wrapping_shift_impl!(WrappingShr, wrapping_shr, i64);
wrapping_shift_impl!(WrappingShr, wrapping_shr, isize);
#[cfg(has_i128)]
wrapping_shift_impl!(WrappingShr, wrapping_shr, i128);
// Well this is a bit funny, but all the more appropriate.
@@ -297,8 +285,7 @@ fn test_wrapping_traits() {
assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0);
assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0);
assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0);
// TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
// only added to core::num::Wrapping<_> in Rust 1.10.
assert_eq!(wrapping_neg(255), (-Wrapping(255u8)).0);
assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
}
@@ -321,8 +308,11 @@ fn wrapping_is_wrappingmul() {
require_wrappingmul(&Wrapping(42));
}
// TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
// only added to core::num::Wrapping<_> in Rust 1.10.
#[test]
fn wrapping_is_wrappingneg() {
fn require_wrappingneg<T: WrappingNeg>(_: &T) {}
require_wrappingneg(&Wrapping(42));
}
#[test]
fn wrapping_is_wrappingshl() {

View File

@@ -1,6 +1,6 @@
use crate::{CheckedMul, One};
use core::num::Wrapping;
use core::ops::Mul;
use {CheckedMul, One};
/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
@@ -99,22 +99,14 @@ pow_impl!(i64, u16, u32, i64::pow);
pow_impl!(i64, u32, u32, i64::pow);
pow_impl!(i64, usize);
#[cfg(has_i128)]
pow_impl!(u128, u8, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u16, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u32, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, usize);
#[cfg(has_i128)]
pow_impl!(i128, u8, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u16, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u32, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, usize);
pow_impl!(usize, u8, u32, usize::pow);
@@ -133,9 +125,7 @@ pow_impl!(Wrapping<u32>);
pow_impl!(Wrapping<i32>);
pow_impl!(Wrapping<u64>);
pow_impl!(Wrapping<i64>);
#[cfg(has_i128)]
pow_impl!(Wrapping<u128>);
#[cfg(has_i128)]
pow_impl!(Wrapping<i128>);
pow_impl!(Wrapping<usize>);
pow_impl!(Wrapping<isize>);
@@ -155,7 +145,7 @@ pow_impl!(Wrapping<isize>);
#[cfg(any(feature = "std", feature = "libm"))]
mod float_impls {
use super::Pow;
use Float;
use crate::Float;
pow_impl!(f32, i8, i32, <f32 as Float>::powi);
pow_impl!(f32, u8, i32, <f32 as Float>::powi);
@@ -232,18 +222,8 @@ pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) ->
return Some(T::one());
}
macro_rules! optry {
($expr:expr) => {
if let Some(val) = $expr {
val
} else {
return None;
}
};
}
while exp & 1 == 0 {
base = optry!(base.checked_mul(&base));
base = base.checked_mul(&base)?;
exp >>= 1;
}
if exp == 1 {
@@ -253,9 +233,9 @@ pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) ->
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
base = base.checked_mul(&base)?;
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
acc = acc.checked_mul(&base)?;
}
}
Some(acc)

View File

@@ -2,7 +2,7 @@
use core::ops::Neg;
use {Float, Num, NumCast};
use crate::{Float, Num, NumCast};
// NOTE: These doctests have the same issue as those in src/float.rs.
// They're testing the inherent methods directly, and not those of `Real`.
@@ -270,7 +270,7 @@ pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// Take the square root of a number.
///
/// Returns NaN if `self` is a negative floating-point number.
/// Returns NaN if `self` is a negative floating-point number.
///
/// # Panics
///

View File

@@ -1,8 +1,8 @@
use core::num::Wrapping;
use core::ops::Neg;
use float::FloatCore;
use Num;
use crate::float::FloatCore;
use crate::Num;
/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
@@ -72,10 +72,7 @@ macro_rules! signed_impl {
)*)
}
signed_impl!(isize i8 i16 i32 i64);
#[cfg(has_i128)]
signed_impl!(i128);
signed_impl!(isize i8 i16 i32 i64 i128);
impl<T: Signed> Signed for Wrapping<T>
where
@@ -202,9 +199,7 @@ macro_rules! empty_trait_impl {
)*)
}
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
#[cfg(has_i128)]
empty_trait_impl!(Unsigned for u128);
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64 u128);
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
@@ -214,11 +209,8 @@ fn unsigned_wrapping_is_unsigned() {
require_unsigned(&Wrapping(42_u32));
}
// Commenting this out since it doesn't compile on Rust 1.8,
// because on this version Wrapping doesn't implement Neg and therefore can't
// implement Signed.
// #[test]
// fn signed_wrapping_is_signed() {
// fn require_signed<T: Signed>(_: &T) {}
// require_signed(&Wrapping(-42));
// }
#[test]
fn signed_wrapping_is_signed() {
fn require_signed<T: Signed>(_: &T) {}
require_signed(&Wrapping(-42));
}

View File

@@ -1,21 +1,13 @@
//! Tests of `num_traits::cast`.
#![no_std]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
extern crate num_traits;
#![cfg_attr(not(feature = "std"), no_std)]
use num_traits::cast::*;
use num_traits::Bounded;
use core::{f32, f64};
#[cfg(has_i128)]
use core::{i128, u128};
use core::{i16, i32, i64, i8, isize};
use core::{u16, u32, u64, u8, usize};
use core::{i128, i16, i32, i64, i8, isize};
use core::{u128, u16, u32, u64, u8, usize};
use core::fmt::Debug;
use core::mem;
@@ -147,7 +139,6 @@ fn cast_to_unsigned_int_checks_overflow() {
}
#[test]
#[cfg(has_i128)]
fn cast_to_i128_checks_overflow() {
let big_f: f64 = 1.0e123;
let normal_f: f64 = 1.0;
@@ -163,7 +154,7 @@ fn cast_to_i128_checks_overflow() {
}
#[cfg(feature = "std")]
fn dbg(args: ::core::fmt::Arguments) {
fn dbg(args: ::core::fmt::Arguments<'_>) {
println!("{}", args);
}
@@ -180,9 +171,9 @@ macro_rules! float_test_edge {
let small = if $t::MIN == 0 || mem::size_of::<$t>() < mem::size_of::<$f>() {
$t::MIN as $f - 1.0
} else {
($t::MIN as $f).raw_offset(1).floor()
($t::MIN as $f).raw_inc().floor()
};
let fmin = small.raw_offset(-1);
let fmin = small.raw_dec();
dbg!(" testing min {}\n\tvs. {:.0}\n\tand {:.0}", $t::MIN, fmin, small);
assert_eq!(Some($t::MIN), cast::<$f, $t>($t::MIN as $f));
assert_eq!(Some($t::MIN), cast::<$f, $t>(fmin));
@@ -192,11 +183,11 @@ macro_rules! float_test_edge {
($t::MAX, $t::MAX as $f + 1.0)
} else {
let large = $t::MAX as $f; // rounds up!
let max = large.raw_offset(-1) as $t; // the next smallest possible
let max = large.raw_dec() as $t; // the next smallest possible
assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS);
(max, large)
};
let fmax = large.raw_offset(-1);
let fmax = large.raw_dec();
dbg!(" testing max {}\n\tvs. {:.0}\n\tand {:.0}", max, fmax, large);
assert_eq!(Some(max), cast::<$f, $t>(max as $f));
assert_eq!(Some(max), cast::<$f, $t>(fmax));
@@ -210,27 +201,27 @@ macro_rules! float_test_edge {
}
trait RawOffset: Sized {
type Raw;
fn raw_offset(self, offset: Self::Raw) -> Self;
fn raw_inc(self) -> Self;
fn raw_dec(self) -> Self;
}
impl RawOffset for f32 {
type Raw = i32;
fn raw_offset(self, offset: Self::Raw) -> Self {
unsafe {
let raw: Self::Raw = mem::transmute(self);
mem::transmute(raw + offset)
}
fn raw_inc(self) -> Self {
Self::from_bits(self.to_bits() + 1)
}
fn raw_dec(self) -> Self {
Self::from_bits(self.to_bits() - 1)
}
}
impl RawOffset for f64 {
type Raw = i64;
fn raw_offset(self, offset: Self::Raw) -> Self {
unsafe {
let raw: Self::Raw = mem::transmute(self);
mem::transmute(raw + offset)
}
fn raw_inc(self) -> Self {
Self::from_bits(self.to_bits() + 1)
}
fn raw_dec(self) -> Self {
Self::from_bits(self.to_bits() - 1)
}
}
@@ -243,7 +234,6 @@ fn cast_float_to_int_edge_cases() {
}
#[test]
#[cfg(has_i128)]
fn cast_float_to_i128_edge_cases() {
float_test_edge!(f32 -> i128 u128);
float_test_edge!(f64 -> i128 u128);
@@ -251,6 +241,7 @@ fn cast_float_to_i128_edge_cases() {
macro_rules! int_test_edge {
($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({
#[allow(arithmetic_overflow)] // https://github.com/rust-lang/rust/issues/109731
fn test_edge() {
dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
@@ -302,7 +293,6 @@ fn cast_int_to_int_edge_cases() {
}
#[test]
#[cfg(has_i128)]
fn cast_int_to_128_edge_cases() {
use core::cmp::Ordering::*;