Skip to main content

const_num_traits/
lib.rs

1// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Numeric traits for generic mathematics
12//!
13//! ## Constant-time (CT) tiers
14//!
15//! Every operation trait in this crate is classified by how implementable it
16//! is for constant-time integer types (types whose execution time must not
17//! depend on operand *values*):
18//!
19//! - **Tier A — CT-implementable**: branchless on the data; secret values
20//!   flow only through arithmetic/bitwise instructions. Examples: the
21//!   `Wrapping*`/`Overflowing*`/`Carrying*` families, [`PrimBits`],
22//!   [`Midpoint`], [`AbsDiff`], [`CastSigned`], lossy [`Truncate`].
23//! - **Tier B — caller-leaky**: the operation itself can be implemented
24//!   branchlessly, but the `bool`/`Option` return type invites branching on
25//!   secret-derived data at the call site. Examples: the `Checked*` family,
26//!   [`Parity`], [`IsPowerOfTwo`], [`HighestOne`]. With the `ct` cargo
27//!   feature, masked counterparts returning `subtle::Choice`/`CtOption`
28//!   are available in `ops::ct`.
29//! - **Tier C — CT-hostile**: data-dependent control flow, division, or
30//!   data-dependent panics. Examples: everything `Div`/`Rem`-based
31//!   ([`Euclid`], [`DivCeil`], [`Ilog10`], [`NextMultipleOf`]), the
32//!   `Strict*` family (panics on a data-dependent condition),
33//!   [`Num::from_str_radix`].
34//!
35//! **Public-parameter convention**: shift amounts, rotation counts,
36//! exponents and logarithm bases are treated as *public* values — branching
37//! on them does not demote a trait from Tier A/B. If your shift amount is
38//! itself a secret, none of these traits are appropriate as-is.
39//!
40//! The tier of each trait family is noted in its module documentation
41//! under [`ops`]. Rule of thumb maintained by this crate: a Tier-A trait
42//! never has a Tier-C supertrait, and never requires
43//! `PartialEq`/`Ord`/`Div`/`Rem`.
44//!
45//! ## Compatibility
46//!
47//! The `const-num-traits` crate is tested for rustc 1.86 and greater.
48
49#![deny(unconditional_recursion)]
50// By-value receivers mirror core's inherent methods, so `is_*` predicates take
51// `self` by value — intentional, though clippy's `wrong_self_convention` flags it.
52#![allow(clippy::wrong_self_convention)]
53// The const parsers (`from_ascii`, the float `from_str_radix`) can't call the
54// non-const `RangeInclusive::contains`, so they spell range checks out longhand.
55#![allow(clippy::manual_range_contains)]
56#![no_std]
57#![cfg_attr(
58    feature = "nightly",
59    feature(const_trait_impl, const_ops, const_cmp, const_destruct)
60)]
61// docs.rs sets `--cfg docsrs`; enable `doc(cfg(...))` so feature-gated items
62// (e.g. the `ct` module) render with a "Available on crate feature …" label.
63#![cfg_attr(docsrs, feature(doc_cfg))]
64
65// Need to explicitly bring the crate in for inherent float methods
66#[cfg(feature = "std")]
67extern crate std;
68
69use core::fmt;
70use core::num::Wrapping;
71use core::ops::{Add, Div, Mul, Rem, Sub};
72use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
73
74pub use crate::bounds::Bounded;
75#[cfg(any(feature = "std", feature = "libm"))]
76pub use crate::float::Float;
77pub use crate::float::FloatConst;
78// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use const_num_traits::*;`.
79pub use crate::cast::{AsPrimitive, FromPrimitive, NumCast, ToPrimitive, cast};
80pub use crate::identities::{ConstOne, ConstZero, One, Zero, one, zero};
81pub use crate::int::{PrimBits, PrimInt};
82pub use crate::ops::bits::{
83    BitWidth, BitsPrecision, DepositBits, ExtractBits, FunnelShl, FunnelShr, HighestOne,
84    IsolateHighestOne, IsolateLowestOne, LowestOne, ShlExact, ShrExact, UnboundedShl, UnboundedShr,
85    WithPrecision,
86};
87pub use crate::ops::byte_slice::{ByteSliceError, ByteSliceErrorKind, FromByteSlice};
88pub use crate::ops::bytes::{FromBytes, ToBytes};
89pub use crate::ops::carrying::{BorrowingSub, CarryingAdd, CarryingMul, WideningMul};
90pub use crate::ops::checked::{
91    CheckedAbs, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedPow, CheckedRem, CheckedShl,
92    CheckedShr, CheckedSub,
93};
94pub use crate::ops::clmul::{CarryingCarrylessMul, CarrylessMul, WideningCarrylessMul};
95pub use crate::ops::convert::{
96    AbsDiff, CastSigned, CastUnsigned, CheckedCast, ClampMagnitude, SaturatingCast, StrictCast,
97    Truncate, UnsignedAbs, Widen, WrappingCast,
98};
99#[cfg(feature = "ct")]
100#[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
101pub use crate::ops::ct::{
102    CtCheckedAdd, CtCheckedMul, CtCheckedNeg, CtCheckedSignedDiff, CtCheckedSub, CtIsPowerOfTwo,
103    CtIsZero, CtParity,
104};
105pub use crate::ops::euclid::{CheckedEuclid, Euclid, OverflowingEuclid, WrappingEuclid};
106pub use crate::ops::float_ops::{
107    Algebraic, Erf, FloatBits, Gamma, Maximum, Minimum, NextDown, NextUp, RoundTiesEven,
108};
109pub use crate::ops::from_ascii::{AsciiErrorKind, AsciiParseError, FromAscii};
110pub use crate::ops::inv::Inv;
111pub use crate::ops::log::{Ilog, Ilog2, Ilog10};
112pub use crate::ops::mixed::{
113    CheckedAddSigned, CheckedAddUnsigned, CheckedSignedDiff, CheckedSubSigned, CheckedSubUnsigned,
114    OverflowingAddSigned, OverflowingAddUnsigned, OverflowingSubSigned, OverflowingSubUnsigned,
115    SaturatingAddSigned, SaturatingAddUnsigned, SaturatingSubSigned, SaturatingSubUnsigned,
116    StrictAddSigned, StrictAddUnsigned, StrictSubSigned, StrictSubUnsigned, WrappingAddSigned,
117    WrappingAddUnsigned, WrappingSubSigned, WrappingSubUnsigned,
118};
119pub use crate::ops::mul_add::{MulAdd, MulAddAssign};
120pub use crate::ops::overflowing::{
121    OverflowingAbs, OverflowingAdd, OverflowingDiv, OverflowingMul, OverflowingNeg, OverflowingPow,
122    OverflowingRem, OverflowingShl, OverflowingShr, OverflowingSub,
123};
124pub use crate::ops::parity::Parity;
125pub use crate::ops::pow2::{IsPowerOfTwo, NextPowerOfTwo};
126pub use crate::ops::rounding::{DivCeil, DivExact, DivFloor, Midpoint, MultipleOf, NextMultipleOf};
127pub use crate::ops::saturating::{
128    Saturating, SaturatingAbs, SaturatingAdd, SaturatingDiv, SaturatingMul, SaturatingNeg,
129    SaturatingPow, SaturatingSub,
130};
131pub use crate::ops::sqrt::{CheckedIsqrt, Isqrt};
132pub use crate::ops::strict::{
133    StrictAbs, StrictAdd, StrictDiv, StrictEuclid, StrictMul, StrictNeg, StrictPow, StrictRem,
134    StrictShl, StrictShr, StrictSub,
135};
136#[cfg(feature = "ct")]
137#[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
138pub use crate::ops::typestate::CtNonZero;
139pub use crate::ops::typestate::{
140    BitIndex, BitIndexOps, DivNonZero, Even, Finite, HasNonZero, NonMin, NonNegative, Odd,
141    Positive, PowerOfTwo, PowerOfTwoOps, TypestateError,
142};
143pub use crate::ops::wrapping::{
144    WrappingAbs, WrappingAdd, WrappingDiv, WrappingMul, WrappingNeg, WrappingPow, WrappingRem,
145    WrappingShl, WrappingShr, WrappingSub,
146};
147pub use crate::personality::{
148    Ct, HasPersonality, Nct, Personality, PersonalityMarker, PersonalityTag,
149};
150pub use crate::pow::{Pow, checked_pow, pow};
151pub use crate::sign::{Signed, Signum, Unsigned, abs, abs_sub, signum};
152
153#[macro_use]
154mod macros;
155
156pub mod bounds;
157pub mod cast;
158pub mod float;
159pub mod identities;
160pub mod int;
161pub mod ops;
162pub mod personality;
163pub mod pow;
164pub mod real;
165pub mod sign;
166
167/// One-stop trait import: `use const_num_traits::prelude::*;`
168///
169/// Brings every trait in the crate into scope — both the num-traits-compatible
170/// bundles and the fine-grained modern atoms. This matters after the
171/// bundle-to-supertrait extractions: with only a bundle
172/// imported (e.g. `PrimInt`), method-syntax calls to methods that moved to a
173/// supertrait (e.g. `count_ones` on `PrimBits`) don't resolve on concrete
174/// non-primitive types. Importing the prelude makes that a non-issue.
175pub mod prelude {
176    pub use crate::bounds::*;
177    pub use crate::cast::*;
178    pub use crate::float::*;
179    pub use crate::identities::*;
180    pub use crate::int::*;
181    pub use crate::ops::bits::*;
182    pub use crate::ops::byte_slice::*;
183    pub use crate::ops::bytes::*;
184    pub use crate::ops::carrying::*;
185    pub use crate::ops::checked::*;
186    pub use crate::ops::clmul::*;
187    pub use crate::ops::convert::*;
188    #[cfg(feature = "ct")]
189    #[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
190    pub use crate::ops::ct::*;
191    pub use crate::ops::euclid::*;
192    pub use crate::ops::float_ops::*;
193    pub use crate::ops::from_ascii::*;
194    pub use crate::ops::inv::*;
195    pub use crate::ops::log::*;
196    pub use crate::ops::mixed::*;
197    pub use crate::ops::mul_add::*;
198    pub use crate::ops::overflowing::*;
199    pub use crate::ops::parity::*;
200    pub use crate::ops::pow2::*;
201    pub use crate::ops::rounding::*;
202    pub use crate::personality::*;
203    // typestate *traits* only (for method resolution); the wrapper *types*
204    // (`PowerOfTwo`/`Odd`/`Even`/`Positive`/`NonNegative`) stay crate-root-only,
205    // so the glob doesn't inject those generic names into consumers.
206    pub use crate::ops::saturating::*;
207    pub use crate::ops::sqrt::*;
208    pub use crate::ops::strict::*;
209    #[cfg(feature = "ct")]
210    #[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
211    pub use crate::ops::typestate::CtNonZero;
212    pub use crate::ops::typestate::{BitIndexOps, DivNonZero, HasNonZero, PowerOfTwoOps};
213    pub use crate::ops::wrapping::*;
214    pub use crate::pow::*;
215    #[cfg(any(feature = "std", feature = "libm"))]
216    pub use crate::real::*;
217    pub use crate::sign::*;
218    pub use crate::{
219        FromStrRadix, Num, NumAssign, NumAssignOps, NumAssignRef, NumOps, NumRef, RefNum, RingOps,
220    };
221}
222
223c0nst::c0nst! {
224/// The base trait for numeric types, covering `0` and `1` values,
225/// comparisons, basic numeric operations, and string conversion.
226pub c0nst trait Num: [c0nst] PartialEq + [c0nst] Zero + [c0nst] One + [c0nst] NumOps {
227    type FromStrRadixErr;
228
229    /// Convert from a string and radix (typically `2..=36`).
230    ///
231    /// # Examples
232    ///
233    /// ```rust
234    /// use const_num_traits::Num;
235    ///
236    /// let result = <i32 as Num>::from_str_radix("27", 10);
237    /// assert_eq!(result, Ok(27));
238    ///
239    /// let result = <i32 as Num>::from_str_radix("foo", 10);
240    /// assert!(result.is_err());
241    /// ```
242    ///
243    /// # Supported radices
244    ///
245    /// The exact range of supported radices is at the discretion of each type implementation. For
246    /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the
247    /// standard library, which **panic** if the radix is not in the range from 2 to 36. The
248    /// implementation in this crate for primitive floats is similar.
249    ///
250    /// For third-party types, it is suggested that implementations should follow suit and at least
251    /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix.
252    /// It's possible that a type might not even support the common radix 10, nor any, if string
253    /// parsing doesn't make sense for that type.
254    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
255}
256}
257
258c0nst::c0nst! {
259/// Generic trait for types implementing the division-free basic numeric
260/// operations: addition, subtraction and multiplication.
261///
262/// This is the aggregation to bound on when the type may not expose
263/// division — e.g. constant-time integers, where division is inherently
264/// data-dependent. [`NumOps`] extends it with `Div` and `Rem`.
265///
266/// This is automatically implemented for types which implement the operators.
267pub c0nst trait RingOps<Rhs = Self, Output = Self>:
268    [c0nst] Add<Rhs, Output = Output>
269    + [c0nst] Sub<Rhs, Output = Output>
270    + [c0nst] Mul<Rhs, Output = Output>
271{
272}
273}
274
275c0nst::c0nst! {
276c0nst impl<T, Rhs, Output> RingOps<Rhs, Output> for T where
277    T: [c0nst] Add<Rhs, Output = Output>
278        + [c0nst] Sub<Rhs, Output = Output>
279        + [c0nst] Mul<Rhs, Output = Output>
280{
281}
282}
283
284c0nst::c0nst! {
285/// Generic trait for types implementing basic numeric operations
286///
287/// This is automatically implemented for types which implement the operators.
288pub c0nst trait NumOps<Rhs = Self, Output = Self>:
289    [c0nst] RingOps<Rhs, Output>
290    + [c0nst] Div<Rhs, Output = Output>
291    + [c0nst] Rem<Rhs, Output = Output>
292{
293}
294}
295
296c0nst::c0nst! {
297c0nst impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
298    T: [c0nst] Add<Rhs, Output = Output>
299        + [c0nst] Sub<Rhs, Output = Output>
300        + [c0nst] Mul<Rhs, Output = Output>
301        + [c0nst] Div<Rhs, Output = Output>
302        + [c0nst] Rem<Rhs, Output = Output>
303{
304}
305}
306
307c0nst::c0nst! {
308/// The trait for `Num` types which also implement numeric operations taking
309/// the second operand by reference.
310///
311/// This is automatically implemented for types which implement the operators.
312pub c0nst trait NumRef: [c0nst] Num + for<'r> [c0nst] NumOps<&'r Self> {}
313}
314c0nst::c0nst! {
315c0nst impl<T> NumRef for T where T: [c0nst] Num + for<'r> [c0nst] NumOps<&'r T> {}
316}
317
318c0nst::c0nst! {
319/// The trait for `Num` references which implement numeric operations, taking the
320/// second operand either by value or by reference.
321///
322/// This is automatically implemented for all types which implement the operators. It covers
323/// every type implementing the operations though, regardless of it being a reference or
324/// related to `Num`.
325pub c0nst trait RefNum<Base>: [c0nst] NumOps<Base, Base> + for<'r> [c0nst] NumOps<&'r Base, Base> {}
326}
327c0nst::c0nst! {
328c0nst impl<T, Base> RefNum<Base> for T where T: [c0nst] NumOps<Base, Base> + for<'r> [c0nst] NumOps<&'r Base, Base> {}
329}
330
331c0nst::c0nst! {
332/// Generic trait for types implementing numeric assignment operators (like `+=`).
333///
334/// This is automatically implemented for types which implement the operators.
335pub c0nst trait NumAssignOps<Rhs = Self>:
336    [c0nst] AddAssign<Rhs> + [c0nst] SubAssign<Rhs> + [c0nst] MulAssign<Rhs> + [c0nst] DivAssign<Rhs> + [c0nst] RemAssign<Rhs>
337{
338}
339}
340
341c0nst::c0nst! {
342c0nst impl<T, Rhs> NumAssignOps<Rhs> for T where
343    T: [c0nst] AddAssign<Rhs> + [c0nst] SubAssign<Rhs> + [c0nst] MulAssign<Rhs> + [c0nst] DivAssign<Rhs> + [c0nst] RemAssign<Rhs>
344{
345}
346}
347
348c0nst::c0nst! {
349/// The trait for `Num` types which also implement assignment operators.
350///
351/// This is automatically implemented for types which implement the operators.
352pub c0nst trait NumAssign: [c0nst] Num + [c0nst] NumAssignOps {}
353}
354c0nst::c0nst! {
355c0nst impl<T> NumAssign for T where T: [c0nst] Num + [c0nst] NumAssignOps {}
356}
357
358c0nst::c0nst! {
359/// The trait for `NumAssign` types which also implement assignment operations
360/// taking the second operand by reference.
361///
362/// This is automatically implemented for types which implement the operators.
363pub c0nst trait NumAssignRef: [c0nst] NumAssign + for<'r> [c0nst] NumAssignOps<&'r Self> {}
364}
365c0nst::c0nst! {
366c0nst impl<T> NumAssignRef for T where T: [c0nst] NumAssign + for<'r> [c0nst] NumAssignOps<&'r T> {}
367}
368
369/// Conversion from a string in a given radix.
370///
371/// This is the standalone atom for the parsing capability that [`Num`]
372/// bundles; implement both for full compatibility. (`Num` keeps its own
373/// `FromStrRadixErr` associated type and method because associated types
374/// can't be re-exported through supertraits.)
375///
376/// This is a plain (never-const) trait: string parsing is not
377/// const-evaluable for any of the primitive types today.
378pub trait FromStrRadix: Sized {
379    /// The parse error type.
380    type Err;
381
382    /// Convert from a string and radix (typically `2..=36`); see
383    /// [`Num::from_str_radix`] for the conventions around supported
384    /// radices.
385    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err>;
386}
387
388macro_rules! from_str_radix_atom_impl {
389    ($($t:ty)*) => ($(
390        impl FromStrRadix for $t {
391            type Err = ::core::num::ParseIntError;
392            #[inline]
393            fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::Err> {
394                <$t>::from_str_radix(s, radix)
395            }
396        }
397    )*)
398}
399from_str_radix_atom_impl!(usize u8 u16 u32 u64 u128);
400from_str_radix_atom_impl!(isize i8 i16 i32 i64 i128);
401
402macro_rules! from_str_radix_atom_float_impl {
403    ($($t:ty)*) => ($(
404        impl FromStrRadix for $t {
405            type Err = ParseFloatError;
406            #[inline]
407            fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::Err> {
408                // reuse the crate's float radix parser through the Num impl
409                <$t as Num>::from_str_radix(s, radix)
410            }
411        }
412    )*)
413}
414
415impl<T: FromStrRadix> FromStrRadix for Wrapping<T> {
416    type Err = T::Err;
417    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err> {
418        T::from_str_radix(str, radix).map(Wrapping)
419    }
420}
421
422impl<T: FromStrRadix> FromStrRadix for core::num::Saturating<T> {
423    type Err = T::Err;
424    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err> {
425        T::from_str_radix(str, radix).map(core::num::Saturating)
426    }
427}
428
429macro_rules! int_trait_impl {
430    ($name:ident for $($t:ty)*) => ($(
431        c0nst::c0nst! {
432        c0nst impl $name for $t {
433            type FromStrRadixErr = ::core::num::ParseIntError;
434            #[inline]
435            fn from_str_radix(s: &str, radix: u32)
436                              -> Result<Self, ::core::num::ParseIntError>
437            {
438                <$t>::from_str_radix(s, radix)
439            }
440        }
441        }
442    )*)
443}
444int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
445int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
446
447// Wrapping<T>'s `PartialEq` impl in std isn't const yet, so this stays a
448// non-const impl of the (otherwise const) `Num` trait.
449impl<T: Num> Num for Wrapping<T>
450where
451    Wrapping<T>: NumOps,
452{
453    type FromStrRadixErr = T::FromStrRadixErr;
454    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
455        T::from_str_radix(str, radix).map(Wrapping)
456    }
457}
458
459// Same caveat as Wrapping<T>: no const PartialEq impl in std.
460impl<T: Num> Num for core::num::Saturating<T>
461where
462    core::num::Saturating<T>: NumOps,
463{
464    type FromStrRadixErr = T::FromStrRadixErr;
465    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
466        T::from_str_radix(str, radix).map(core::num::Saturating)
467    }
468}
469
470#[derive(Debug)]
471pub enum FloatErrorKind {
472    Empty,
473    Invalid,
474}
475// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
476// so there's not really any way for us to reuse it.
477#[derive(Debug)]
478pub struct ParseFloatError {
479    pub kind: FloatErrorKind,
480}
481
482impl fmt::Display for ParseFloatError {
483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484        let description = match self.kind {
485            FloatErrorKind::Empty => "cannot parse float from empty string",
486            FloatErrorKind::Invalid => "invalid float literal",
487        };
488
489        description.fmt(f)
490    }
491}
492
493fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
494    a.len() == b.len()
495        && a.bytes().zip(b.bytes()).all(|(a, b)| {
496            let a_to_ascii_lower = a | ((a.is_ascii_uppercase() as u8) << 5);
497            a_to_ascii_lower == b
498        })
499}
500
501// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
502// with this implementation ourselves until we want to make a breaking change.
503// (would have to drop it from `Num` though)
504//
505// Non-const impl of the const `Num` trait: this parser uses iterators,
506// `Result::map_err`, `?`, and `str::parse`, none of which are const.
507macro_rules! float_trait_impl {
508    ($name:ident for $($t:ident)*) => ($(
509        impl $name for $t {
510            type FromStrRadixErr = ParseFloatError;
511
512            fn from_str_radix(src: &str, radix: u32)
513                              -> Result<Self, Self::FromStrRadixErr>
514            {
515                use self::FloatErrorKind::*;
516                use self::ParseFloatError as PFE;
517
518                // Special case radix 10 to use more accurate standard library implementation
519                if radix == 10 {
520                    return src.parse().map_err(|_| PFE {
521                        kind: if src.is_empty() { Empty } else { Invalid },
522                    });
523                }
524
525                // Special values
526                if str_to_ascii_lower_eq_str(src, "inf")
527                    || str_to_ascii_lower_eq_str(src, "infinity")
528                {
529                    return Ok($t::INFINITY);
530                } else if str_to_ascii_lower_eq_str(src, "-inf")
531                    || str_to_ascii_lower_eq_str(src, "-infinity")
532                {
533                    return Ok($t::NEG_INFINITY);
534                } else if str_to_ascii_lower_eq_str(src, "nan") {
535                    return Ok($t::NAN);
536                } else if str_to_ascii_lower_eq_str(src, "-nan") {
537                    return Ok(-$t::NAN);
538                }
539
540                fn slice_shift_char(src: &str) -> Option<(char, &str)> {
541                    let mut chars = src.chars();
542                    Some((chars.next()?, chars.as_str()))
543                }
544
545                let (is_positive, src) =  match slice_shift_char(src) {
546                    None             => return Err(PFE { kind: Empty }),
547                    Some(('-', ""))  => return Err(PFE { kind: Empty }),
548                    Some(('-', src)) => (false, src),
549                    Some((_, _))     => (true,  src),
550                };
551
552                // The significand to accumulate
553                let mut sig = if is_positive { 0.0 } else { -0.0 };
554                // Necessary to detect overflow
555                let mut prev_sig = sig;
556                let mut cs = src.chars().enumerate();
557                // Exponent prefix and exponent index offset
558                let mut exp_info = None::<(char, usize)>;
559
560                // Parse the integer part of the significand
561                for (i, c) in cs.by_ref() {
562                    match c.to_digit(radix) {
563                        Some(digit) => {
564                            // shift significand one digit left
565                            sig *= radix as $t;
566
567                            // add/subtract current digit depending on sign
568                            if is_positive {
569                                sig += (digit as isize) as $t;
570                            } else {
571                                sig -= (digit as isize) as $t;
572                            }
573
574                            // Detect overflow by comparing to last value, except
575                            // if we've not seen any non-zero digits.
576                            if prev_sig != 0.0 {
577                                if is_positive && sig <= prev_sig
578                                    { return Ok($t::INFINITY); }
579                                if !is_positive && sig >= prev_sig
580                                    { return Ok($t::NEG_INFINITY); }
581
582                                // Detect overflow by reversing the shift-and-add process
583                                if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
584                                    { return Ok($t::INFINITY); }
585                                if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
586                                    { return Ok($t::NEG_INFINITY); }
587                            }
588                            prev_sig = sig;
589                        },
590                        None => match c {
591                            'e' | 'E' | 'p' | 'P' => {
592                                exp_info = Some((c, i + 1));
593                                break;  // start of exponent
594                            },
595                            '.' => {
596                                break;  // start of fractional part
597                            },
598                            _ => {
599                                return Err(PFE { kind: Invalid });
600                            },
601                        },
602                    }
603                }
604
605                // If we are not yet at the exponent parse the fractional
606                // part of the significand
607                if exp_info.is_none() {
608                    let mut power = 1.0;
609                    for (i, c) in cs.by_ref() {
610                        match c.to_digit(radix) {
611                            Some(digit) => {
612                                // Decrease power one order of magnitude
613                                power /= radix as $t;
614                                // add/subtract current digit depending on sign
615                                sig = if is_positive {
616                                    sig + (digit as $t) * power
617                                } else {
618                                    sig - (digit as $t) * power
619                                };
620                                // Detect overflow by comparing to last value
621                                if is_positive && sig < prev_sig
622                                    { return Ok($t::INFINITY); }
623                                if !is_positive && sig > prev_sig
624                                    { return Ok($t::NEG_INFINITY); }
625                                prev_sig = sig;
626                            },
627                            None => match c {
628                                'e' | 'E' | 'p' | 'P' => {
629                                    exp_info = Some((c, i + 1));
630                                    break; // start of exponent
631                                },
632                                _ => {
633                                    return Err(PFE { kind: Invalid });
634                                },
635                            },
636                        }
637                    }
638                }
639
640                // Parse and calculate the exponent
641                let exp = match exp_info {
642                    Some((c, offset)) => {
643                        let base = match c {
644                            'E' | 'e' if radix == 10 => 10.0,
645                            'P' | 'p' if radix == 16 => 2.0,
646                            _ => return Err(PFE { kind: Invalid }),
647                        };
648
649                        // Parse the exponent as decimal integer
650                        let src = &src[offset..];
651                        let (is_positive, exp) = match slice_shift_char(src) {
652                            Some(('-', src)) => (false, src.parse::<usize>()),
653                            Some(('+', src)) => (true,  src.parse::<usize>()),
654                            Some((_, _))     => (true,  src.parse::<usize>()),
655                            None             => return Err(PFE { kind: Invalid }),
656                        };
657
658                        #[cfg(feature = "std")]
659                        fn pow(base: $t, exp: usize) -> $t {
660                            Float::powi(base, exp as i32)
661                        }
662                        // otherwise uses the generic `pow` from the root
663
664                        match (is_positive, exp) {
665                            (true,  Ok(exp)) => pow(base, exp),
666                            (false, Ok(exp)) => 1.0 / pow(base, exp),
667                            (_, Err(_))      => return Err(PFE { kind: Invalid }),
668                        }
669                    },
670                    None => 1.0, // no exponent
671                };
672
673                Ok(sig * exp)
674            }
675        }
676    )*)
677}
678float_trait_impl!(Num for f32 f64);
679from_str_radix_atom_float_impl!(f32 f64);
680
681c0nst::c0nst! {
682/// A value bounded by a minimum and a maximum
683///
684///  If input is less than min then this returns min.
685///  If input is greater than max then this returns max.
686///  Otherwise this returns input.
687///
688/// **Panics** in debug mode if `!(min <= max)`.
689#[inline]
690pub c0nst fn clamp<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, min: T, max: T) -> T {
691    debug_assert!(min <= max, "min must be less than or equal to max");
692    if input < min {
693        min
694    } else if input > max {
695        max
696    } else {
697        input
698    }
699}
700}
701
702c0nst::c0nst! {
703/// A value bounded by a minimum value
704///
705///  If input is less than min then this returns min.
706///  Otherwise this returns input.
707///  `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
708///
709/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
710#[inline]
711#[allow(clippy::eq_op)]
712pub c0nst fn clamp_min<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, min: T) -> T {
713    debug_assert!(min == min, "min must not be NAN");
714    if input < min {
715        min
716    } else {
717        input
718    }
719}
720}
721
722c0nst::c0nst! {
723/// A value bounded by a maximum value
724///
725///  If input is greater than max then this returns max.
726///  Otherwise this returns input.
727///  `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
728///
729/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
730#[inline]
731#[allow(clippy::eq_op)]
732pub c0nst fn clamp_max<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, max: T) -> T {
733    debug_assert!(max == max, "max must not be NAN");
734    if input > max {
735        max
736    } else {
737        input
738    }
739}
740}
741
742#[test]
743fn clamp_test() {
744    // Int test
745    assert_eq!(1, clamp(1, -1, 2));
746    assert_eq!(-1, clamp(-2, -1, 2));
747    assert_eq!(2, clamp(3, -1, 2));
748    assert_eq!(1, clamp_min(1, -1));
749    assert_eq!(-1, clamp_min(-2, -1));
750    assert_eq!(-1, clamp_max(1, -1));
751    assert_eq!(-2, clamp_max(-2, -1));
752
753    // Float test
754    assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
755    assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
756    assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
757    assert_eq!(1.0, clamp_min(1.0, -1.0));
758    assert_eq!(-1.0, clamp_min(-2.0, -1.0));
759    assert_eq!(-1.0, clamp_max(1.0, -1.0));
760    assert_eq!(-2.0, clamp_max(-2.0, -1.0));
761    assert!(clamp(f32::NAN, -1.0, 1.0).is_nan());
762    assert!(clamp_min(f32::NAN, 1.0).is_nan());
763    assert!(clamp_max(f32::NAN, 1.0).is_nan());
764}
765
766#[test]
767#[should_panic]
768#[cfg(debug_assertions)]
769fn clamp_nan_min() {
770    clamp(0., f32::NAN, 1.);
771}
772
773#[test]
774#[should_panic]
775#[cfg(debug_assertions)]
776fn clamp_nan_max() {
777    clamp(0., -1., f32::NAN);
778}
779
780#[test]
781#[should_panic]
782#[cfg(debug_assertions)]
783fn clamp_nan_min_max() {
784    clamp(0., f32::NAN, f32::NAN);
785}
786
787#[test]
788#[should_panic]
789#[cfg(debug_assertions)]
790fn clamp_min_nan_min() {
791    clamp_min(0., f32::NAN);
792}
793
794#[test]
795#[should_panic]
796#[cfg(debug_assertions)]
797fn clamp_max_nan_max() {
798    clamp_max(0., f32::NAN);
799}
800
801#[test]
802fn from_str_radix_unwrap() {
803    // The Result error must impl Debug to allow unwrap()
804
805    let i: i32 = Num::from_str_radix("0", 10).unwrap();
806    assert_eq!(i, 0);
807
808    let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
809    assert_eq!(f, 0.0);
810}
811
812#[test]
813fn from_str_radix_multi_byte_fail() {
814    // Ensure parsing doesn't panic, even on invalid sign characters
815    assert!(<f32 as Num>::from_str_radix("™0.2", 10).is_err());
816
817    // Even when parsing the exponent sign
818    assert!(<f32 as Num>::from_str_radix("0.2E™1", 10).is_err());
819}
820
821#[test]
822fn from_str_radix_ignore_case() {
823    assert_eq!(
824        <f32 as Num>::from_str_radix("InF", 16).unwrap(),
825        f32::INFINITY
826    );
827    assert_eq!(
828        <f32 as Num>::from_str_radix("InfinitY", 16).unwrap(),
829        f32::INFINITY
830    );
831    assert_eq!(
832        <f32 as Num>::from_str_radix("-InF", 8).unwrap(),
833        f32::NEG_INFINITY
834    );
835    assert_eq!(
836        <f32 as Num>::from_str_radix("-InfinitY", 8).unwrap(),
837        f32::NEG_INFINITY
838    );
839    assert!(<f32 as Num>::from_str_radix("nAn", 4).unwrap().is_nan());
840    assert!(<f32 as Num>::from_str_radix("-nAn", 4).unwrap().is_nan());
841}
842
843#[test]
844fn wrapping_is_num() {
845    fn require_num<T: Num>(_: &T) {}
846    require_num(&Wrapping(42_u32));
847    require_num(&Wrapping(-42));
848}
849
850#[test]
851fn wrapping_from_str_radix() {
852    macro_rules! test_wrapping_from_str_radix {
853        ($($t:ty)+) => {
854            $(
855                for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
856                    let w = <Wrapping<$t> as Num>::from_str_radix(s, r).map(|w| w.0);
857                    assert_eq!(w, <$t as Num>::from_str_radix(s, r));
858                }
859            )+
860        };
861    }
862
863    test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
864}
865
866#[test]
867fn saturating_is_num() {
868    fn require_num<T: Num>(_: &T) {}
869    require_num(&core::num::Saturating(42_u32));
870    require_num(&core::num::Saturating(-42));
871}
872
873#[test]
874fn saturating_from_str_radix() {
875    macro_rules! test_saturating_from_str_radix {
876        ($($t:ty)+) => {
877            $(
878                for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
879                    let w = <core::num::Saturating<$t> as Num>::from_str_radix(s, r).map(|w| w.0);
880                    assert_eq!(w, <$t as Num>::from_str_radix(s, r));
881                }
882            )+
883        };
884    }
885
886    test_saturating_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
887}
888
889#[test]
890fn check_num_ops() {
891    fn compute<T: Num + Copy>(x: T, y: T) -> T {
892        x * y / y % y + y - y
893    }
894    assert_eq!(compute(1, 2), 1)
895}
896
897#[test]
898fn check_numref_ops() {
899    fn compute<T: NumRef>(x: T, y: &T) -> T {
900        x * y / y % y + y - y
901    }
902    assert_eq!(compute(1, &2), 1)
903}
904
905#[test]
906fn check_refnum_ops() {
907    fn compute<T: Copy>(x: &T, y: T) -> T
908    where
909        for<'a> &'a T: RefNum<T>,
910    {
911        &(&(&(&(x * y) / y) % y) + y) - y
912    }
913    assert_eq!(compute(&1, 2), 1)
914}
915
916#[test]
917fn check_refref_ops() {
918    fn compute<T>(x: &T, y: &T) -> T
919    where
920        for<'a> &'a T: RefNum<T>,
921    {
922        &(&(&(&(x * y) / y) % y) + y) - y
923    }
924    assert_eq!(compute(&1, &2), 1)
925}
926
927#[test]
928fn check_numassign_ops() {
929    fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
930        x *= y;
931        x /= y;
932        x %= y;
933        x += y;
934        x -= y;
935        x
936    }
937    assert_eq!(compute(1, 2), 1)
938}
939
940#[test]
941fn check_numassignref_ops() {
942    fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {
943        x *= y;
944        x /= y;
945        x %= y;
946        x += y;
947        x -= y;
948        x
949    }
950    assert_eq!(compute(1, &2), 1)
951}