diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/num-traits/src/lib.rs | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/num-traits/src/lib.rs')
-rw-r--r-- | third_party/rust/num-traits/src/lib.rs | 640 |
1 files changed, 640 insertions, 0 deletions
diff --git a/third_party/rust/num-traits/src/lib.rs b/third_party/rust/num-traits/src/lib.rs new file mode 100644 index 0000000000..bed87f3667 --- /dev/null +++ b/third_party/rust/num-traits/src/lib.rs @@ -0,0 +1,640 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Numeric traits for generic mathematics +//! +//! ## Compatibility +//! +//! The `num-traits` crate is tested for rustc 1.8 and greater. + +#![doc(html_root_url = "https://docs.rs/num-traits/0.2")] +#![deny(unconditional_recursion)] +#![no_std] +#[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; +#[cfg(any(feature = "std", feature = "libm"))] +pub use float::Float; +pub use float::FloatConst; +// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. +pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; +pub use identities::{one, zero, One, Zero}; +pub use int::PrimInt; +pub use 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::{ + WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, +}; +pub use pow::{checked_pow, pow, Pow}; +pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; + +#[macro_use] +mod macros; + +pub mod bounds; +pub mod cast; +pub mod float; +pub mod identities; +pub mod int; +pub mod ops; +pub mod pow; +pub mod real; +pub mod sign; + +/// The base trait for numeric types, covering `0` and `1` values, +/// comparisons, basic numeric operations, and string conversion. +pub trait Num: PartialEq + Zero + One + NumOps { + type FromStrRadixErr; + + /// Convert from a string and radix (typically `2..=36`). + /// + /// # Examples + /// + /// ```rust + /// use num_traits::Num; + /// + /// let result = <i32 as Num>::from_str_radix("27", 10); + /// assert_eq!(result, Ok(27)); + /// + /// let result = <i32 as Num>::from_str_radix("foo", 10); + /// assert!(result.is_err()); + /// ``` + /// + /// # Supported radices + /// + /// The exact range of supported radices is at the discretion of each type implementation. For + /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the + /// standard library, which **panic** if the radix is not in the range from 2 to 36. The + /// implementation in this crate for primitive floats is similar. + /// + /// For third-party types, it is suggested that implementations should follow suit and at least + /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix. + /// It's possible that a type might not even support the common radix 10, nor any, if string + /// parsing doesn't make sense for that type. + fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>; +} + +/// Generic trait for types implementing basic numeric operations +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumOps<Rhs = Self, Output = Self>: + Add<Rhs, Output = Output> + + Sub<Rhs, Output = Output> + + Mul<Rhs, Output = Output> + + Div<Rhs, Output = Output> + + Rem<Rhs, Output = Output> +{ +} + +impl<T, Rhs, Output> NumOps<Rhs, Output> for T where + T: Add<Rhs, Output = Output> + + Sub<Rhs, Output = Output> + + Mul<Rhs, Output = Output> + + Div<Rhs, Output = Output> + + Rem<Rhs, Output = Output> +{ +} + +/// The trait for `Num` types which also implement numeric operations taking +/// the second operand by reference. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumRef: Num + for<'r> NumOps<&'r Self> {} +impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {} + +/// The trait for `Num` references which implement numeric operations, taking the +/// second operand either by value or by reference. +/// +/// This is automatically implemented for all types which implement the operators. It covers +/// every type implementing the operations though, regardless of it being a reference or +/// related to `Num`. +pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {} +impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {} + +/// Generic trait for types implementing numeric assignment operators (like `+=`). +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssignOps<Rhs = Self>: + AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs> +{ +} + +impl<T, Rhs> NumAssignOps<Rhs> for T where + T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs> +{ +} + +/// The trait for `Num` types which also implement assignment operators. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssign: Num + NumAssignOps {} +impl<T> NumAssign for T where T: Num + NumAssignOps {} + +/// The trait for `NumAssign` types which also implement assignment operations +/// taking the second operand by reference. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} +impl<T> 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 = ::core::num::ParseIntError; + #[inline] + fn from_str_radix(s: &str, radix: u32) + -> Result<Self, ::core::num::ParseIntError> + { + <$t>::from_str_radix(s, radix) + } + } + )*) +} +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); + +impl<T: Num> Num for Wrapping<T> +where + Wrapping<T>: NumOps, +{ + type FromStrRadixErr = T::FromStrRadixErr; + fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { + T::from_str_radix(str, radix).map(Wrapping) + } +} + +#[derive(Debug)] +pub enum FloatErrorKind { + Empty, + Invalid, +} +// 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 { + pub kind: FloatErrorKind, +} + +impl fmt::Display for ParseFloatError { + 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", + }; + + description.fmt(f) + } +} + +fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool { + a.len() == b.len() + && a.bytes().zip(b.bytes()).all(|(a, b)| { + let a_to_ascii_lower = a | (((b'A' <= a && a <= b'Z') as u8) << 5); + a_to_ascii_lower == b + }) +} + +// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck +// 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:ident)*) => ($( + impl $name for $t { + type FromStrRadixErr = ParseFloatError; + + fn from_str_radix(src: &str, radix: u32) + -> Result<Self, Self::FromStrRadixErr> + { + use self::FloatErrorKind::*; + use self::ParseFloatError as PFE; + + // Special case radix 10 to use more accurate standard library implementation + if radix == 10 { + return src.parse().map_err(|_| PFE { + kind: if src.is_empty() { Empty } else { Invalid }, + }); + } + + // Special values + if str_to_ascii_lower_eq_str(src, "inf") + || str_to_ascii_lower_eq_str(src, "infinity") + { + return Ok(core::$t::INFINITY); + } else if str_to_ascii_lower_eq_str(src, "-inf") + || str_to_ascii_lower_eq_str(src, "-infinity") + { + return Ok(core::$t::NEG_INFINITY); + } else if str_to_ascii_lower_eq_str(src, "nan") { + return Ok(core::$t::NAN); + } else if str_to_ascii_lower_eq_str(src, "-nan") { + return Ok(-core::$t::NAN); + } + + 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 + } + } + + let (is_positive, src) = match slice_shift_char(src) { + None => return Err(PFE { kind: Empty }), + Some(('-', "")) => return Err(PFE { kind: Empty }), + Some(('-', src)) => (false, src), + Some((_, _)) => (true, src), + }; + + // The significand to accumulate + let mut sig = if is_positive { 0.0 } else { -0.0 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, usize)>; + + // Parse the integer part of the significand + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // shift significand one digit left + sig = sig * (radix as $t); + + // add/subtract current digit depending on sign + if is_positive { + sig = sig + ((digit as isize) as $t); + } else { + sig = sig - ((digit as isize) as $t); + } + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if prev_sig != 0.0 { + if is_positive && sig <= prev_sig + { return Ok(core::$t::INFINITY); } + if !is_positive && sig >= prev_sig + { 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(core::$t::INFINITY); } + if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t) + { return Ok(core::$t::NEG_INFINITY); } + } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = 1.0; + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // Decrease power one order of magnitude + power = power / (radix as $t); + // add/subtract current digit depending on sign + sig = if is_positive { + sig + (digit as $t) * power + } else { + sig - (digit as $t) * power + }; + // Detect overflow by comparing to last value + if is_positive && sig < prev_sig + { return Ok(core::$t::INFINITY); } + if !is_positive && sig > prev_sig + { return Ok(core::$t::NEG_INFINITY); } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + } + + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base = match c { + 'E' | 'e' if radix == 10 => 10.0, + 'P' | 'p' if radix == 16 => 2.0, + _ => return Err(PFE { kind: Invalid }), + }; + + // Parse the exponent as decimal integer + let src = &src[offset..]; + let (is_positive, exp) = match slice_shift_char(src) { + Some(('-', src)) => (false, src.parse::<usize>()), + Some(('+', src)) => (true, src.parse::<usize>()), + Some((_, _)) => (true, src.parse::<usize>()), + 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)) => pow(base, exp), + (false, Ok(exp)) => 1.0 / pow(base, exp), + (_, Err(_)) => return Err(PFE { kind: Invalid }), + } + }, + None => 1.0, // no exponent + }; + + Ok(sig * exp) + } + } + )*) +} +float_trait_impl!(Num for f32 f64); + +/// 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)`. +#[inline] +pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T { + debug_assert!(min <= max, "min must be less than or equal to max"); + if input < min { + min + } else if input > max { + max + } else { + input + } +} + +/// A value bounded by a minimum value +/// +/// If input is less than min then this returns min. +/// Otherwise this returns input. +/// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`. +/// +/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.) +#[inline] +pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T { + debug_assert!(min == min, "min must not be NAN"); + if input < min { + min + } else { + input + } +} + +/// A value bounded by a maximum value +/// +/// If input is greater than max then this returns max. +/// Otherwise this returns input. +/// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`. +/// +/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.) +#[inline] +pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T { + debug_assert!(max == max, "max must not be NAN"); + if input > max { + max + } else { + input + } +} + +#[test] +fn clamp_test() { + // Int test + assert_eq!(1, clamp(1, -1, 2)); + assert_eq!(-1, clamp(-2, -1, 2)); + assert_eq!(2, clamp(3, -1, 2)); + assert_eq!(1, clamp_min(1, -1)); + assert_eq!(-1, clamp_min(-2, -1)); + assert_eq!(-1, clamp_max(1, -1)); + assert_eq!(-2, clamp_max(-2, -1)); + + // Float test + assert_eq!(1.0, clamp(1.0, -1.0, 2.0)); + assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0)); + assert_eq!(2.0, clamp(3.0, -1.0, 2.0)); + assert_eq!(1.0, clamp_min(1.0, -1.0)); + assert_eq!(-1.0, clamp_min(-2.0, -1.0)); + assert_eq!(-1.0, clamp_max(1.0, -1.0)); + assert_eq!(-2.0, clamp_max(-2.0, -1.0)); + assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan()); + assert!(clamp_min(::core::f32::NAN, 1.0).is_nan()); + assert!(clamp_max(::core::f32::NAN, 1.0).is_nan()); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +fn clamp_nan_min() { + clamp(0., ::core::f32::NAN, 1.); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +fn clamp_nan_max() { + clamp(0., -1., ::core::f32::NAN); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +fn clamp_nan_min_max() { + clamp(0., ::core::f32::NAN, ::core::f32::NAN); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +fn clamp_min_nan_min() { + clamp_min(0., ::core::f32::NAN); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +fn clamp_max_nan_max() { + clamp_max(0., ::core::f32::NAN); +} + +#[test] +fn from_str_radix_unwrap() { + // The Result error must impl Debug to allow unwrap() + + let i: i32 = Num::from_str_radix("0", 10).unwrap(); + assert_eq!(i, 0); + + let f: f32 = Num::from_str_radix("0.0", 10).unwrap(); + assert_eq!(f, 0.0); +} + +#[test] +fn from_str_radix_multi_byte_fail() { + // Ensure parsing doesn't panic, even on invalid sign characters + assert!(f32::from_str_radix("™0.2", 10).is_err()); + + // Even when parsing the exponent sign + assert!(f32::from_str_radix("0.2E™1", 10).is_err()); +} + +#[test] +fn from_str_radix_ignore_case() { + assert_eq!( + f32::from_str_radix("InF", 16).unwrap(), + ::core::f32::INFINITY + ); + assert_eq!( + f32::from_str_radix("InfinitY", 16).unwrap(), + ::core::f32::INFINITY + ); + assert_eq!( + f32::from_str_radix("-InF", 8).unwrap(), + ::core::f32::NEG_INFINITY + ); + assert_eq!( + f32::from_str_radix("-InfinitY", 8).unwrap(), + ::core::f32::NEG_INFINITY + ); + assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan()); + assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan()); +} + +#[test] +fn wrapping_is_num() { + fn require_num<T: Num>(_: &T) {} + require_num(&Wrapping(42_u32)); + require_num(&Wrapping(-42)); +} + +#[test] +fn wrapping_from_str_radix() { + macro_rules! test_wrapping_from_str_radix { + ($($t:ty)+) => { + $( + for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] { + let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0); + assert_eq!(w, <$t as Num>::from_str_radix(s, r)); + } + )+ + }; + } + + test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[test] +fn check_num_ops() { + fn compute<T: Num + Copy>(x: T, y: T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, 2), 1) +} + +#[test] +fn check_numref_ops() { + fn compute<T: NumRef>(x: T, y: &T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, &2), 1) +} + +#[test] +fn check_refnum_ops() { + fn compute<T: Copy>(x: &T, y: T) -> T + where + for<'a> &'a T: RefNum<T>, + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, 2), 1) +} + +#[test] +fn check_refref_ops() { + fn compute<T>(x: &T, y: &T) -> T + where + for<'a> &'a T: RefNum<T>, + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, &2), 1) +} + +#[test] +fn check_numassign_ops() { + fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T { + x *= y; + x /= y; + x %= y; + x += y; + x -= y; + x + } + 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 { + x *= y; + x /= y; + x %= y; + x += y; + x -= y; + x + } + assert_eq!(compute(1, &2), 1) +} |