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, 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
167pub 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 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! {
224pub c0nst trait Num: [c0nst] PartialEq + [c0nst] Zero + [c0nst] One + [c0nst] NumOps {
227 type FromStrRadixErr;
228
229 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
255}
256}
257
258c0nst::c0nst! {
259pub 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! {
285pub 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! {
308pub 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! {
319pub 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! {
332pub 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! {
349pub 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! {
359pub 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
369pub trait FromStrRadix: Sized {
379 type Err;
381
382 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 <$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
447impl<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
459impl<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#[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
501macro_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 if radix == 10 {
520 return src.parse().map_err(|_| PFE {
521 kind: if src.is_empty() { Empty } else { Invalid },
522 });
523 }
524
525 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 let mut sig = if is_positive { 0.0 } else { -0.0 };
554 let mut prev_sig = sig;
556 let mut cs = src.chars().enumerate();
557 let mut exp_info = None::<(char, usize)>;
559
560 for (i, c) in cs.by_ref() {
562 match c.to_digit(radix) {
563 Some(digit) => {
564 sig *= radix as $t;
566
567 if is_positive {
569 sig += (digit as isize) as $t;
570 } else {
571 sig -= (digit as isize) as $t;
572 }
573
574 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 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; },
595 '.' => {
596 break; },
598 _ => {
599 return Err(PFE { kind: Invalid });
600 },
601 },
602 }
603 }
604
605 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 power /= radix as $t;
614 sig = if is_positive {
616 sig + (digit as $t) * power
617 } else {
618 sig - (digit as $t) * power
619 };
620 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; },
632 _ => {
633 return Err(PFE { kind: Invalid });
634 },
635 },
636 }
637 }
638 }
639
640 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 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 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, };
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#[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#[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#[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 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 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 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 assert!(<f32 as Num>::from_str_radix("™0.2", 10).is_err());
816
817 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}