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