1#![deny(unconditional_recursion)]
50#![allow(clippy::wrong_self_convention)]
53#![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#![cfg_attr(docsrs, feature(doc_cfg))]
64
65#[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;
78pub 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::byte_slice::{ByteSliceError, ByteSliceErrorKind, FromByteSlice};
87pub use crate::ops::bytes::{FromBytes, ToBytes};
88pub use crate::ops::carrying::{BorrowingSub, CarryingAdd, CarryingMul, WideningMul};
89pub use crate::ops::checked::{
90 CheckedAbs, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedPow, CheckedRem, CheckedShl,
91 CheckedShr, CheckedSub,
92};
93pub use crate::ops::clmul::{CarryingCarrylessMul, CarrylessMul, WideningCarrylessMul};
94pub use crate::ops::convert::{
95 AbsDiff, CastSigned, CastUnsigned, CheckedCast, ClampMagnitude, SaturatingCast, StrictCast,
96 Truncate, UnsignedAbs, Widen, WrappingCast,
97};
98#[cfg(feature = "ct")]
99#[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
100pub use crate::ops::ct::{
101 CtCheckedAdd, CtCheckedMul, CtCheckedNeg, CtCheckedSignedDiff, CtCheckedSub, CtIsPowerOfTwo,
102 CtIsZero, CtParity,
103};
104pub use crate::ops::euclid::{CheckedEuclid, Euclid, OverflowingEuclid, WrappingEuclid};
105pub use crate::ops::float_ops::{
106 Algebraic, Erf, FloatBits, Gamma, Maximum, Minimum, NextDown, NextUp, RoundTiesEven,
107};
108pub use crate::ops::from_ascii::{AsciiErrorKind, AsciiParseError, FromAscii};
109pub use crate::ops::inv::Inv;
110pub use crate::ops::log::{Ilog, Ilog2, Ilog10};
111pub use crate::ops::mixed::{
112 CheckedAddSigned, CheckedAddUnsigned, CheckedSignedDiff, CheckedSubSigned, CheckedSubUnsigned,
113 OverflowingAddSigned, OverflowingAddUnsigned, OverflowingSubSigned, OverflowingSubUnsigned,
114 SaturatingAddSigned, SaturatingAddUnsigned, SaturatingSubSigned, SaturatingSubUnsigned,
115 StrictAddSigned, StrictAddUnsigned, StrictSubSigned, StrictSubUnsigned, WrappingAddSigned,
116 WrappingAddUnsigned, WrappingSubSigned, WrappingSubUnsigned,
117};
118pub use crate::ops::mul_add::{MulAdd, MulAddAssign};
119pub use crate::ops::overflowing::{
120 OverflowingAbs, OverflowingAdd, OverflowingDiv, OverflowingMul, OverflowingNeg, OverflowingPow,
121 OverflowingRem, OverflowingShl, OverflowingShr, OverflowingSub,
122};
123pub use crate::ops::parity::Parity;
124pub use crate::ops::pow2::{IsPowerOfTwo, NextPowerOfTwo};
125pub use crate::ops::rounding::{DivCeil, DivExact, DivFloor, Midpoint, MultipleOf, NextMultipleOf};
126pub use crate::ops::saturating::{
127 Saturating, SaturatingAbs, SaturatingAdd, SaturatingDiv, SaturatingMul, SaturatingNeg,
128 SaturatingPow, SaturatingSub,
129};
130pub use crate::ops::sqrt::{CheckedIsqrt, Isqrt};
131pub use crate::ops::strict::{
132 StrictAbs, StrictAdd, StrictDiv, StrictEuclid, StrictMul, StrictNeg, StrictPow, StrictRem,
133 StrictShl, StrictShr, StrictSub,
134};
135#[cfg(feature = "ct")]
136#[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
137pub use crate::ops::typestate::CtNonZero;
138pub use crate::ops::typestate::{
139 BitIndex, BitIndexOps, DivNonZero, Even, Finite, HasNonZero, NonMin, NonNegative, Odd,
140 Positive, PowerOfTwo, PowerOfTwoOps, TypestateError,
141};
142pub use crate::ops::wrapping::{
143 WrappingAbs, WrappingAdd, WrappingDiv, WrappingMul, WrappingNeg, WrappingPow, WrappingRem,
144 WrappingShl, WrappingShr, WrappingSub,
145};
146pub use crate::personality::{
147 Ct, HasPersonality, Nct, Personality, PersonalityMarker, PersonalityTag,
148};
149pub use crate::pow::{Pow, checked_pow, pow};
150pub use crate::sign::{Signed, Signum, Unsigned, abs, abs_sub, signum};
151
152#[macro_use]
153mod macros;
154
155pub mod bounds;
156pub mod cast;
157pub mod float;
158pub mod identities;
159pub mod int;
160pub mod ops;
161pub mod personality;
162pub mod pow;
163pub mod real;
164pub mod sign;
165
166pub mod prelude {
175 pub use crate::bounds::*;
176 pub use crate::cast::*;
177 pub use crate::float::*;
178 pub use crate::identities::*;
179 pub use crate::int::*;
180 pub use crate::ops::bits::*;
181 pub use crate::ops::byte_slice::*;
182 pub use crate::ops::bytes::*;
183 pub use crate::ops::carrying::*;
184 pub use crate::ops::checked::*;
185 pub use crate::ops::clmul::*;
186 pub use crate::ops::convert::*;
187 #[cfg(feature = "ct")]
188 #[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
189 pub use crate::ops::ct::*;
190 pub use crate::ops::euclid::*;
191 pub use crate::ops::float_ops::*;
192 pub use crate::ops::from_ascii::*;
193 pub use crate::ops::inv::*;
194 pub use crate::ops::log::*;
195 pub use crate::ops::mixed::*;
196 pub use crate::ops::mul_add::*;
197 pub use crate::ops::overflowing::*;
198 pub use crate::ops::parity::*;
199 pub use crate::ops::pow2::*;
200 pub use crate::ops::rounding::*;
201 pub use crate::personality::*;
202 pub use crate::ops::saturating::*;
206 pub use crate::ops::sqrt::*;
207 pub use crate::ops::strict::*;
208 #[cfg(feature = "ct")]
209 #[cfg_attr(docsrs, doc(cfg(feature = "ct")))]
210 pub use crate::ops::typestate::CtNonZero;
211 pub use crate::ops::typestate::{BitIndexOps, DivNonZero, HasNonZero, PowerOfTwoOps};
212 pub use crate::ops::wrapping::*;
213 pub use crate::pow::*;
214 #[cfg(any(feature = "std", feature = "libm"))]
215 pub use crate::real::*;
216 pub use crate::sign::*;
217 pub use crate::{
218 FromStrRadix, Num, NumAssign, NumAssignOps, NumAssignRef, NumOps, NumRef, RefNum, RingOps,
219 };
220}
221
222c0nst::c0nst! {
223pub c0nst trait Num: [c0nst] PartialEq + [c0nst] Zero + [c0nst] One + [c0nst] NumOps {
226 type FromStrRadixErr;
227
228 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
254}
255}
256
257c0nst::c0nst! {
258pub c0nst trait RingOps<Rhs = Self, Output = Self>:
267 [c0nst] Add<Rhs, Output = Output>
268 + [c0nst] Sub<Rhs, Output = Output>
269 + [c0nst] Mul<Rhs, Output = Output>
270{
271}
272}
273
274c0nst::c0nst! {
275c0nst impl<T, Rhs, Output> RingOps<Rhs, Output> for T where
276 T: [c0nst] Add<Rhs, Output = Output>
277 + [c0nst] Sub<Rhs, Output = Output>
278 + [c0nst] Mul<Rhs, Output = Output>
279{
280}
281}
282
283c0nst::c0nst! {
284pub c0nst trait NumOps<Rhs = Self, Output = Self>:
288 [c0nst] RingOps<Rhs, Output>
289 + [c0nst] Div<Rhs, Output = Output>
290 + [c0nst] Rem<Rhs, Output = Output>
291{
292}
293}
294
295c0nst::c0nst! {
296c0nst impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
297 T: [c0nst] Add<Rhs, Output = Output>
298 + [c0nst] Sub<Rhs, Output = Output>
299 + [c0nst] Mul<Rhs, Output = Output>
300 + [c0nst] Div<Rhs, Output = Output>
301 + [c0nst] Rem<Rhs, Output = Output>
302{
303}
304}
305
306c0nst::c0nst! {
307pub c0nst trait NumRef: [c0nst] Num + for<'r> [c0nst] NumOps<&'r Self> {}
312}
313c0nst::c0nst! {
314c0nst impl<T> NumRef for T where T: [c0nst] Num + for<'r> [c0nst] NumOps<&'r T> {}
315}
316
317c0nst::c0nst! {
318pub c0nst trait RefNum<Base>: [c0nst] NumOps<Base, Base> + for<'r> [c0nst] NumOps<&'r Base, Base> {}
325}
326c0nst::c0nst! {
327c0nst impl<T, Base> RefNum<Base> for T where T: [c0nst] NumOps<Base, Base> + for<'r> [c0nst] NumOps<&'r Base, Base> {}
328}
329
330c0nst::c0nst! {
331pub c0nst trait NumAssignOps<Rhs = Self>:
335 [c0nst] AddAssign<Rhs> + [c0nst] SubAssign<Rhs> + [c0nst] MulAssign<Rhs> + [c0nst] DivAssign<Rhs> + [c0nst] RemAssign<Rhs>
336{
337}
338}
339
340c0nst::c0nst! {
341c0nst impl<T, Rhs> NumAssignOps<Rhs> for T where
342 T: [c0nst] AddAssign<Rhs> + [c0nst] SubAssign<Rhs> + [c0nst] MulAssign<Rhs> + [c0nst] DivAssign<Rhs> + [c0nst] RemAssign<Rhs>
343{
344}
345}
346
347c0nst::c0nst! {
348pub c0nst trait NumAssign: [c0nst] Num + [c0nst] NumAssignOps {}
352}
353c0nst::c0nst! {
354c0nst impl<T> NumAssign for T where T: [c0nst] Num + [c0nst] NumAssignOps {}
355}
356
357c0nst::c0nst! {
358pub c0nst trait NumAssignRef: [c0nst] NumAssign + for<'r> [c0nst] NumAssignOps<&'r Self> {}
363}
364c0nst::c0nst! {
365c0nst impl<T> NumAssignRef for T where T: [c0nst] NumAssign + for<'r> [c0nst] NumAssignOps<&'r T> {}
366}
367
368pub trait FromStrRadix: Sized {
378 type Err;
380
381 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err>;
385}
386
387macro_rules! from_str_radix_atom_impl {
388 ($($t:ty)*) => ($(
389 impl FromStrRadix for $t {
390 type Err = ::core::num::ParseIntError;
391 #[inline]
392 fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::Err> {
393 <$t>::from_str_radix(s, radix)
394 }
395 }
396 )*)
397}
398from_str_radix_atom_impl!(usize u8 u16 u32 u64 u128);
399from_str_radix_atom_impl!(isize i8 i16 i32 i64 i128);
400
401macro_rules! from_str_radix_atom_float_impl {
402 ($($t:ty)*) => ($(
403 impl FromStrRadix for $t {
404 type Err = ParseFloatError;
405 #[inline]
406 fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::Err> {
407 <$t as Num>::from_str_radix(s, radix)
409 }
410 }
411 )*)
412}
413
414impl<T: FromStrRadix> FromStrRadix for Wrapping<T> {
415 type Err = T::Err;
416 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err> {
417 T::from_str_radix(str, radix).map(Wrapping)
418 }
419}
420
421impl<T: FromStrRadix> FromStrRadix for core::num::Saturating<T> {
422 type Err = T::Err;
423 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::Err> {
424 T::from_str_radix(str, radix).map(core::num::Saturating)
425 }
426}
427
428macro_rules! int_trait_impl {
429 ($name:ident for $($t:ty)*) => ($(
430 c0nst::c0nst! {
431 c0nst impl $name for $t {
432 type FromStrRadixErr = ::core::num::ParseIntError;
433 #[inline]
434 fn from_str_radix(s: &str, radix: u32)
435 -> Result<Self, ::core::num::ParseIntError>
436 {
437 <$t>::from_str_radix(s, radix)
438 }
439 }
440 }
441 )*)
442}
443int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
444int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
445
446impl<T: Num> Num for Wrapping<T>
449where
450 Wrapping<T>: NumOps,
451{
452 type FromStrRadixErr = T::FromStrRadixErr;
453 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
454 T::from_str_radix(str, radix).map(Wrapping)
455 }
456}
457
458impl<T: Num> Num for core::num::Saturating<T>
460where
461 core::num::Saturating<T>: NumOps,
462{
463 type FromStrRadixErr = T::FromStrRadixErr;
464 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
465 T::from_str_radix(str, radix).map(core::num::Saturating)
466 }
467}
468
469#[derive(Debug)]
470pub enum FloatErrorKind {
471 Empty,
472 Invalid,
473}
474#[derive(Debug)]
477pub struct ParseFloatError {
478 pub kind: FloatErrorKind,
479}
480
481impl fmt::Display for ParseFloatError {
482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483 let description = match self.kind {
484 FloatErrorKind::Empty => "cannot parse float from empty string",
485 FloatErrorKind::Invalid => "invalid float literal",
486 };
487
488 description.fmt(f)
489 }
490}
491
492fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
493 a.len() == b.len()
494 && a.bytes().zip(b.bytes()).all(|(a, b)| {
495 let a_to_ascii_lower = a | ((a.is_ascii_uppercase() as u8) << 5);
496 a_to_ascii_lower == b
497 })
498}
499
500macro_rules! float_trait_impl {
507 ($name:ident for $($t:ident)*) => ($(
508 impl $name for $t {
509 type FromStrRadixErr = ParseFloatError;
510
511 fn from_str_radix(src: &str, radix: u32)
512 -> Result<Self, Self::FromStrRadixErr>
513 {
514 use self::FloatErrorKind::*;
515 use self::ParseFloatError as PFE;
516
517 if radix == 10 {
519 return src.parse().map_err(|_| PFE {
520 kind: if src.is_empty() { Empty } else { Invalid },
521 });
522 }
523
524 if str_to_ascii_lower_eq_str(src, "inf")
526 || str_to_ascii_lower_eq_str(src, "infinity")
527 {
528 return Ok($t::INFINITY);
529 } else if str_to_ascii_lower_eq_str(src, "-inf")
530 || str_to_ascii_lower_eq_str(src, "-infinity")
531 {
532 return Ok($t::NEG_INFINITY);
533 } else if str_to_ascii_lower_eq_str(src, "nan") {
534 return Ok($t::NAN);
535 } else if str_to_ascii_lower_eq_str(src, "-nan") {
536 return Ok(-$t::NAN);
537 }
538
539 fn slice_shift_char(src: &str) -> Option<(char, &str)> {
540 let mut chars = src.chars();
541 Some((chars.next()?, chars.as_str()))
542 }
543
544 let (is_positive, src) = match slice_shift_char(src) {
545 None => return Err(PFE { kind: Empty }),
546 Some(('-', "")) => return Err(PFE { kind: Empty }),
547 Some(('-', src)) => (false, src),
548 Some((_, _)) => (true, src),
549 };
550
551 let mut sig = if is_positive { 0.0 } else { -0.0 };
553 let mut prev_sig = sig;
555 let mut cs = src.chars().enumerate();
556 let mut exp_info = None::<(char, usize)>;
558
559 for (i, c) in cs.by_ref() {
561 match c.to_digit(radix) {
562 Some(digit) => {
563 sig *= radix as $t;
565
566 if is_positive {
568 sig += (digit as isize) as $t;
569 } else {
570 sig -= (digit as isize) as $t;
571 }
572
573 if prev_sig != 0.0 {
576 if is_positive && sig <= prev_sig
577 { return Ok($t::INFINITY); }
578 if !is_positive && sig >= prev_sig
579 { return Ok($t::NEG_INFINITY); }
580
581 if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
583 { return Ok($t::INFINITY); }
584 if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
585 { return Ok($t::NEG_INFINITY); }
586 }
587 prev_sig = sig;
588 },
589 None => match c {
590 'e' | 'E' | 'p' | 'P' => {
591 exp_info = Some((c, i + 1));
592 break; },
594 '.' => {
595 break; },
597 _ => {
598 return Err(PFE { kind: Invalid });
599 },
600 },
601 }
602 }
603
604 if exp_info.is_none() {
607 let mut power = 1.0;
608 for (i, c) in cs.by_ref() {
609 match c.to_digit(radix) {
610 Some(digit) => {
611 power /= radix as $t;
613 sig = if is_positive {
615 sig + (digit as $t) * power
616 } else {
617 sig - (digit as $t) * power
618 };
619 if is_positive && sig < prev_sig
621 { return Ok($t::INFINITY); }
622 if !is_positive && sig > prev_sig
623 { return Ok($t::NEG_INFINITY); }
624 prev_sig = sig;
625 },
626 None => match c {
627 'e' | 'E' | 'p' | 'P' => {
628 exp_info = Some((c, i + 1));
629 break; },
631 _ => {
632 return Err(PFE { kind: Invalid });
633 },
634 },
635 }
636 }
637 }
638
639 let exp = match exp_info {
641 Some((c, offset)) => {
642 let base = match c {
643 'E' | 'e' if radix == 10 => 10.0,
644 'P' | 'p' if radix == 16 => 2.0,
645 _ => return Err(PFE { kind: Invalid }),
646 };
647
648 let src = &src[offset..];
650 let (is_positive, exp) = match slice_shift_char(src) {
651 Some(('-', src)) => (false, src.parse::<usize>()),
652 Some(('+', src)) => (true, src.parse::<usize>()),
653 Some((_, _)) => (true, src.parse::<usize>()),
654 None => return Err(PFE { kind: Invalid }),
655 };
656
657 #[cfg(feature = "std")]
658 fn pow(base: $t, exp: usize) -> $t {
659 Float::powi(base, exp as i32)
660 }
661 match (is_positive, exp) {
664 (true, Ok(exp)) => pow(base, exp),
665 (false, Ok(exp)) => 1.0 / pow(base, exp),
666 (_, Err(_)) => return Err(PFE { kind: Invalid }),
667 }
668 },
669 None => 1.0, };
671
672 Ok(sig * exp)
673 }
674 }
675 )*)
676}
677float_trait_impl!(Num for f32 f64);
678from_str_radix_atom_float_impl!(f32 f64);
679
680c0nst::c0nst! {
681#[inline]
689pub c0nst fn clamp<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, min: T, max: T) -> T {
690 debug_assert!(min <= max, "min must be less than or equal to max");
691 if input < min {
692 min
693 } else if input > max {
694 max
695 } else {
696 input
697 }
698}
699}
700
701c0nst::c0nst! {
702#[inline]
710#[allow(clippy::eq_op)]
711pub c0nst fn clamp_min<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, min: T) -> T {
712 debug_assert!(min == min, "min must not be NAN");
713 if input < min {
714 min
715 } else {
716 input
717 }
718}
719}
720
721c0nst::c0nst! {
722#[inline]
730#[allow(clippy::eq_op)]
731pub c0nst fn clamp_max<T: [c0nst] PartialOrd + [c0nst] Destruct>(input: T, max: T) -> T {
732 debug_assert!(max == max, "max must not be NAN");
733 if input > max {
734 max
735 } else {
736 input
737 }
738}
739}
740
741#[test]
742fn clamp_test() {
743 assert_eq!(1, clamp(1, -1, 2));
745 assert_eq!(-1, clamp(-2, -1, 2));
746 assert_eq!(2, clamp(3, -1, 2));
747 assert_eq!(1, clamp_min(1, -1));
748 assert_eq!(-1, clamp_min(-2, -1));
749 assert_eq!(-1, clamp_max(1, -1));
750 assert_eq!(-2, clamp_max(-2, -1));
751
752 assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
754 assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
755 assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
756 assert_eq!(1.0, clamp_min(1.0, -1.0));
757 assert_eq!(-1.0, clamp_min(-2.0, -1.0));
758 assert_eq!(-1.0, clamp_max(1.0, -1.0));
759 assert_eq!(-2.0, clamp_max(-2.0, -1.0));
760 assert!(clamp(f32::NAN, -1.0, 1.0).is_nan());
761 assert!(clamp_min(f32::NAN, 1.0).is_nan());
762 assert!(clamp_max(f32::NAN, 1.0).is_nan());
763}
764
765#[test]
766#[should_panic]
767#[cfg(debug_assertions)]
768fn clamp_nan_min() {
769 clamp(0., f32::NAN, 1.);
770}
771
772#[test]
773#[should_panic]
774#[cfg(debug_assertions)]
775fn clamp_nan_max() {
776 clamp(0., -1., f32::NAN);
777}
778
779#[test]
780#[should_panic]
781#[cfg(debug_assertions)]
782fn clamp_nan_min_max() {
783 clamp(0., f32::NAN, f32::NAN);
784}
785
786#[test]
787#[should_panic]
788#[cfg(debug_assertions)]
789fn clamp_min_nan_min() {
790 clamp_min(0., f32::NAN);
791}
792
793#[test]
794#[should_panic]
795#[cfg(debug_assertions)]
796fn clamp_max_nan_max() {
797 clamp_max(0., f32::NAN);
798}
799
800#[test]
801fn from_str_radix_unwrap() {
802 let i: i32 = Num::from_str_radix("0", 10).unwrap();
805 assert_eq!(i, 0);
806
807 let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
808 assert_eq!(f, 0.0);
809}
810
811#[test]
812fn from_str_radix_multi_byte_fail() {
813 assert!(<f32 as Num>::from_str_radix("™0.2", 10).is_err());
815
816 assert!(<f32 as Num>::from_str_radix("0.2E™1", 10).is_err());
818}
819
820#[test]
821fn from_str_radix_ignore_case() {
822 assert_eq!(
823 <f32 as Num>::from_str_radix("InF", 16).unwrap(),
824 f32::INFINITY
825 );
826 assert_eq!(
827 <f32 as Num>::from_str_radix("InfinitY", 16).unwrap(),
828 f32::INFINITY
829 );
830 assert_eq!(
831 <f32 as Num>::from_str_radix("-InF", 8).unwrap(),
832 f32::NEG_INFINITY
833 );
834 assert_eq!(
835 <f32 as Num>::from_str_radix("-InfinitY", 8).unwrap(),
836 f32::NEG_INFINITY
837 );
838 assert!(<f32 as Num>::from_str_radix("nAn", 4).unwrap().is_nan());
839 assert!(<f32 as Num>::from_str_radix("-nAn", 4).unwrap().is_nan());
840}
841
842#[test]
843fn wrapping_is_num() {
844 fn require_num<T: Num>(_: &T) {}
845 require_num(&Wrapping(42_u32));
846 require_num(&Wrapping(-42));
847}
848
849#[test]
850fn wrapping_from_str_radix() {
851 macro_rules! test_wrapping_from_str_radix {
852 ($($t:ty)+) => {
853 $(
854 for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
855 let w = <Wrapping<$t> as Num>::from_str_radix(s, r).map(|w| w.0);
856 assert_eq!(w, <$t as Num>::from_str_radix(s, r));
857 }
858 )+
859 };
860 }
861
862 test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
863}
864
865#[test]
866fn saturating_is_num() {
867 fn require_num<T: Num>(_: &T) {}
868 require_num(&core::num::Saturating(42_u32));
869 require_num(&core::num::Saturating(-42));
870}
871
872#[test]
873fn saturating_from_str_radix() {
874 macro_rules! test_saturating_from_str_radix {
875 ($($t:ty)+) => {
876 $(
877 for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
878 let w = <core::num::Saturating<$t> as Num>::from_str_radix(s, r).map(|w| w.0);
879 assert_eq!(w, <$t as Num>::from_str_radix(s, r));
880 }
881 )+
882 };
883 }
884
885 test_saturating_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
886}
887
888#[test]
889fn check_num_ops() {
890 fn compute<T: Num + Copy>(x: T, y: T) -> T {
891 x * y / y % y + y - y
892 }
893 assert_eq!(compute(1, 2), 1)
894}
895
896#[test]
897fn check_numref_ops() {
898 fn compute<T: NumRef>(x: T, y: &T) -> T {
899 x * y / y % y + y - y
900 }
901 assert_eq!(compute(1, &2), 1)
902}
903
904#[test]
905fn check_refnum_ops() {
906 fn compute<T: Copy>(x: &T, y: T) -> T
907 where
908 for<'a> &'a T: RefNum<T>,
909 {
910 &(&(&(&(x * y) / y) % y) + y) - y
911 }
912 assert_eq!(compute(&1, 2), 1)
913}
914
915#[test]
916fn check_refref_ops() {
917 fn compute<T>(x: &T, y: &T) -> T
918 where
919 for<'a> &'a T: RefNum<T>,
920 {
921 &(&(&(&(x * y) / y) % y) + y) - y
922 }
923 assert_eq!(compute(&1, &2), 1)
924}
925
926#[test]
927fn check_numassign_ops() {
928 fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
929 x *= y;
930 x /= y;
931 x %= y;
932 x += y;
933 x -= y;
934 x
935 }
936 assert_eq!(compute(1, 2), 1)
937}
938
939#[test]
940fn check_numassignref_ops() {
941 fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {
942 x *= y;
943 x /= y;
944 x %= y;
945 x += y;
946 x -= y;
947 x
948 }
949 assert_eq!(compute(1, &2), 1)
950}