summaryrefslogtreecommitdiffstats
path: root/third_party/rust/num-traits/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/num-traits/src/lib.rs
parentInitial commit. (diff)
downloadfirefox-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.rs640
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)
+}