Coverage Report

Created: 2025-06-24 06:17

/rust/registry/src/index.crates.io-6f17d22bba15001f/num-traits-0.2.15/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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
//! ## Compatibility
14
//!
15
//! The `num-traits` crate is tested for rustc 1.8 and greater.
16
17
#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
18
#![deny(unconditional_recursion)]
19
#![no_std]
20
#[cfg(feature = "std")]
21
extern crate std;
22
23
// Only `no_std` builds actually use `libm`.
24
#[cfg(all(not(feature = "std"), feature = "libm"))]
25
extern crate libm;
26
27
use core::fmt;
28
use core::num::Wrapping;
29
use core::ops::{Add, Div, Mul, Rem, Sub};
30
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
31
32
pub use bounds::Bounded;
33
#[cfg(any(feature = "std", feature = "libm"))]
34
pub use float::Float;
35
pub use float::FloatConst;
36
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
37
pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
38
pub use identities::{one, zero, One, Zero};
39
pub use int::PrimInt;
40
pub use ops::checked::{
41
    CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
42
};
43
pub use ops::euclid::{CheckedEuclid, Euclid};
44
pub use ops::inv::Inv;
45
pub use ops::mul_add::{MulAdd, MulAddAssign};
46
pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
47
pub use ops::wrapping::{
48
    WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
49
};
50
pub use pow::{checked_pow, pow, Pow};
51
pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
52
53
#[macro_use]
54
mod macros;
55
56
pub mod bounds;
57
pub mod cast;
58
pub mod float;
59
pub mod identities;
60
pub mod int;
61
pub mod ops;
62
pub mod pow;
63
pub mod real;
64
pub mod sign;
65
66
/// The base trait for numeric types, covering `0` and `1` values,
67
/// comparisons, basic numeric operations, and string conversion.
68
pub trait Num: PartialEq + Zero + One + NumOps {
69
    type FromStrRadixErr;
70
71
    /// Convert from a string and radix (typically `2..=36`).
72
    ///
73
    /// # Examples
74
    ///
75
    /// ```rust
76
    /// use num_traits::Num;
77
    ///
78
    /// let result = <i32 as Num>::from_str_radix("27", 10);
79
    /// assert_eq!(result, Ok(27));
80
    ///
81
    /// let result = <i32 as Num>::from_str_radix("foo", 10);
82
    /// assert!(result.is_err());
83
    /// ```
84
    ///
85
    /// # Supported radices
86
    ///
87
    /// The exact range of supported radices is at the discretion of each type implementation. For
88
    /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the
89
    /// standard library, which **panic** if the radix is not in the range from 2 to 36. The
90
    /// implementation in this crate for primitive floats is similar.
91
    ///
92
    /// For third-party types, it is suggested that implementations should follow suit and at least
93
    /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix.
94
    /// It's possible that a type might not even support the common radix 10, nor any, if string
95
    /// parsing doesn't make sense for that type.
96
    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
97
}
98
99
/// Generic trait for types implementing basic numeric operations
100
///
101
/// This is automatically implemented for types which implement the operators.
102
pub trait NumOps<Rhs = Self, Output = Self>:
103
    Add<Rhs, Output = Output>
104
    + Sub<Rhs, Output = Output>
105
    + Mul<Rhs, Output = Output>
106
    + Div<Rhs, Output = Output>
107
    + Rem<Rhs, Output = Output>
108
{
109
}
110
111
impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
112
    T: Add<Rhs, Output = Output>
113
        + Sub<Rhs, Output = Output>
114
        + Mul<Rhs, Output = Output>
115
        + Div<Rhs, Output = Output>
116
        + Rem<Rhs, Output = Output>
117
{
118
}
119
120
/// The trait for `Num` types which also implement numeric operations taking
121
/// the second operand by reference.
122
///
123
/// This is automatically implemented for types which implement the operators.
124
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
125
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
126
127
/// The trait for `Num` references which implement numeric operations, taking the
128
/// second operand either by value or by reference.
129
///
130
/// This is automatically implemented for all types which implement the operators. It covers
131
/// every type implementing the operations though, regardless of it being a reference or
132
/// related to `Num`.
133
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
134
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
135
136
/// Generic trait for types implementing numeric assignment operators (like `+=`).
137
///
138
/// This is automatically implemented for types which implement the operators.
139
pub trait NumAssignOps<Rhs = Self>:
140
    AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
141
{
142
}
143
144
impl<T, Rhs> NumAssignOps<Rhs> for T where
145
    T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
146
{
147
}
148
149
/// The trait for `Num` types which also implement assignment operators.
150
///
151
/// This is automatically implemented for types which implement the operators.
152
pub trait NumAssign: Num + NumAssignOps {}
153
impl<T> NumAssign for T where T: Num + NumAssignOps {}
154
155
/// The trait for `NumAssign` types which also implement assignment operations
156
/// taking the second operand by reference.
157
///
158
/// This is automatically implemented for types which implement the operators.
159
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
160
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
161
162
macro_rules! int_trait_impl {
163
    ($name:ident for $($t:ty)*) => ($(
164
        impl $name for $t {
165
            type FromStrRadixErr = ::core::num::ParseIntError;
166
            #[inline]
167
0
            fn from_str_radix(s: &str, radix: u32)
168
0
                              -> Result<Self, ::core::num::ParseIntError>
169
0
            {
170
0
                <$t>::from_str_radix(s, radix)
171
0
            }
Unexecuted instantiation: <usize as num_traits::Num>::from_str_radix
Unexecuted instantiation: <u8 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <u16 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <u32 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <u64 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <isize as num_traits::Num>::from_str_radix
Unexecuted instantiation: <i8 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <i16 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <i32 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <i64 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <u128 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <i128 as num_traits::Num>::from_str_radix
172
        }
173
    )*)
174
}
175
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
176
#[cfg(has_i128)]
177
int_trait_impl!(Num for u128 i128);
178
179
impl<T: Num> Num for Wrapping<T>
180
where
181
    Wrapping<T>: NumOps,
182
{
183
    type FromStrRadixErr = T::FromStrRadixErr;
184
0
    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
185
0
        T::from_str_radix(str, radix).map(Wrapping)
186
0
    }
187
}
188
189
#[derive(Debug)]
190
pub enum FloatErrorKind {
191
    Empty,
192
    Invalid,
193
}
194
// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
195
// so there's not really any way for us to reuse it.
196
#[derive(Debug)]
197
pub struct ParseFloatError {
198
    pub kind: FloatErrorKind,
199
}
200
201
impl fmt::Display for ParseFloatError {
202
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203
0
        let description = match self.kind {
204
0
            FloatErrorKind::Empty => "cannot parse float from empty string",
205
0
            FloatErrorKind::Invalid => "invalid float literal",
206
        };
207
208
0
        description.fmt(f)
209
0
    }
210
}
211
212
0
fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
213
0
    a.len() == b.len()
214
0
        && a.bytes().zip(b.bytes()).all(|(a, b)| {
215
0
            let a_to_ascii_lower = a | (((b'A' <= a && a <= b'Z') as u8) << 5);
216
0
            a_to_ascii_lower == b
217
0
        })
218
0
}
219
220
// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
221
// with this implementation ourselves until we want to make a breaking change.
222
// (would have to drop it from `Num` though)
223
macro_rules! float_trait_impl {
224
    ($name:ident for $($t:ident)*) => ($(
225
        impl $name for $t {
226
            type FromStrRadixErr = ParseFloatError;
227
228
0
            fn from_str_radix(src: &str, radix: u32)
229
0
                              -> Result<Self, Self::FromStrRadixErr>
230
0
            {
231
                use self::FloatErrorKind::*;
232
                use self::ParseFloatError as PFE;
233
234
                // Special case radix 10 to use more accurate standard library implementation
235
0
                if radix == 10 {
236
0
                    return src.parse().map_err(|_| PFE {
237
0
                        kind: if src.is_empty() { Empty } else { Invalid },
238
0
                    });
Unexecuted instantiation: <f32 as num_traits::Num>::from_str_radix::{closure#0}
Unexecuted instantiation: <f64 as num_traits::Num>::from_str_radix::{closure#0}
239
0
                }
240
0
241
0
                // Special values
242
0
                if str_to_ascii_lower_eq_str(src, "inf")
243
0
                    || str_to_ascii_lower_eq_str(src, "infinity")
244
                {
245
0
                    return Ok(core::$t::INFINITY);
246
0
                } else if str_to_ascii_lower_eq_str(src, "-inf")
247
0
                    || str_to_ascii_lower_eq_str(src, "-infinity")
248
                {
249
0
                    return Ok(core::$t::NEG_INFINITY);
250
0
                } else if str_to_ascii_lower_eq_str(src, "nan") {
251
0
                    return Ok(core::$t::NAN);
252
0
                } else if str_to_ascii_lower_eq_str(src, "-nan") {
253
0
                    return Ok(-core::$t::NAN);
254
0
                }
255
256
0
                fn slice_shift_char(src: &str) -> Option<(char, &str)> {
257
0
                    let mut chars = src.chars();
258
0
                    if let Some(ch) = chars.next() {
259
0
                        Some((ch, chars.as_str()))
260
                    } else {
261
0
                        None
262
                    }
263
0
                }
Unexecuted instantiation: <f32 as num_traits::Num>::from_str_radix::slice_shift_char
Unexecuted instantiation: <f64 as num_traits::Num>::from_str_radix::slice_shift_char
264
265
0
                let (is_positive, src) =  match slice_shift_char(src) {
266
0
                    None             => return Err(PFE { kind: Empty }),
267
0
                    Some(('-', ""))  => return Err(PFE { kind: Empty }),
268
0
                    Some(('-', src)) => (false, src),
269
0
                    Some((_, _))     => (true,  src),
270
                };
271
272
                // The significand to accumulate
273
0
                let mut sig = if is_positive { 0.0 } else { -0.0 };
274
                // Necessary to detect overflow
275
0
                let mut prev_sig = sig;
276
0
                let mut cs = src.chars().enumerate();
277
0
                // Exponent prefix and exponent index offset
278
0
                let mut exp_info = None::<(char, usize)>;
279
280
                // Parse the integer part of the significand
281
0
                for (i, c) in cs.by_ref() {
282
0
                    match c.to_digit(radix) {
283
0
                        Some(digit) => {
284
0
                            // shift significand one digit left
285
0
                            sig = sig * (radix as $t);
286
0
287
0
                            // add/subtract current digit depending on sign
288
0
                            if is_positive {
289
0
                                sig = sig + ((digit as isize) as $t);
290
0
                            } else {
291
0
                                sig = sig - ((digit as isize) as $t);
292
0
                            }
293
294
                            // Detect overflow by comparing to last value, except
295
                            // if we've not seen any non-zero digits.
296
0
                            if prev_sig != 0.0 {
297
0
                                if is_positive && sig <= prev_sig
298
0
                                    { return Ok(core::$t::INFINITY); }
299
0
                                if !is_positive && sig >= prev_sig
300
0
                                    { return Ok(core::$t::NEG_INFINITY); }
301
0
302
0
                                // Detect overflow by reversing the shift-and-add process
303
0
                                if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
304
0
                                    { return Ok(core::$t::INFINITY); }
305
0
                                if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
306
0
                                    { return Ok(core::$t::NEG_INFINITY); }
307
0
                            }
308
0
                            prev_sig = sig;
309
                        },
310
0
                        None => match c {
311
                            'e' | 'E' | 'p' | 'P' => {
312
0
                                exp_info = Some((c, i + 1));
313
0
                                break;  // start of exponent
314
                            },
315
                            '.' => {
316
0
                                break;  // start of fractional part
317
                            },
318
                            _ => {
319
0
                                return Err(PFE { kind: Invalid });
320
                            },
321
                        },
322
                    }
323
                }
324
325
                // If we are not yet at the exponent parse the fractional
326
                // part of the significand
327
0
                if exp_info.is_none() {
328
0
                    let mut power = 1.0;
329
0
                    for (i, c) in cs.by_ref() {
330
0
                        match c.to_digit(radix) {
331
0
                            Some(digit) => {
332
0
                                // Decrease power one order of magnitude
333
0
                                power = power / (radix as $t);
334
0
                                // add/subtract current digit depending on sign
335
0
                                sig = if is_positive {
336
0
                                    sig + (digit as $t) * power
337
                                } else {
338
0
                                    sig - (digit as $t) * power
339
                                };
340
                                // Detect overflow by comparing to last value
341
0
                                if is_positive && sig < prev_sig
342
0
                                    { return Ok(core::$t::INFINITY); }
343
0
                                if !is_positive && sig > prev_sig
344
0
                                    { return Ok(core::$t::NEG_INFINITY); }
345
0
                                prev_sig = sig;
346
                            },
347
0
                            None => match c {
348
                                'e' | 'E' | 'p' | 'P' => {
349
0
                                    exp_info = Some((c, i + 1));
350
0
                                    break; // start of exponent
351
                                },
352
                                _ => {
353
0
                                    return Err(PFE { kind: Invalid });
354
                                },
355
                            },
356
                        }
357
                    }
358
0
                }
359
360
                // Parse and calculate the exponent
361
0
                let exp = match exp_info {
362
0
                    Some((c, offset)) => {
363
0
                        let base = match c {
364
0
                            'E' | 'e' if radix == 10 => 10.0,
365
0
                            'P' | 'p' if radix == 16 => 2.0,
366
0
                            _ => return Err(PFE { kind: Invalid }),
367
                        };
368
369
                        // Parse the exponent as decimal integer
370
0
                        let src = &src[offset..];
371
0
                        let (is_positive, exp) = match slice_shift_char(src) {
372
0
                            Some(('-', src)) => (false, src.parse::<usize>()),
373
0
                            Some(('+', src)) => (true,  src.parse::<usize>()),
374
0
                            Some((_, _))     => (true,  src.parse::<usize>()),
375
0
                            None             => return Err(PFE { kind: Invalid }),
376
                        };
377
378
                        #[cfg(feature = "std")]
379
0
                        fn pow(base: $t, exp: usize) -> $t {
380
0
                            Float::powi(base, exp as i32)
381
0
                        }
Unexecuted instantiation: <f32 as num_traits::Num>::from_str_radix::pow
Unexecuted instantiation: <f64 as num_traits::Num>::from_str_radix::pow
382
                        // otherwise uses the generic `pow` from the root
383
384
0
                        match (is_positive, exp) {
385
0
                            (true,  Ok(exp)) => pow(base, exp),
386
0
                            (false, Ok(exp)) => 1.0 / pow(base, exp),
387
0
                            (_, Err(_))      => return Err(PFE { kind: Invalid }),
388
                        }
389
                    },
390
0
                    None => 1.0, // no exponent
391
                };
392
393
0
                Ok(sig * exp)
394
0
            }
Unexecuted instantiation: <f32 as num_traits::Num>::from_str_radix
Unexecuted instantiation: <f64 as num_traits::Num>::from_str_radix
395
        }
396
    )*)
397
}
398
float_trait_impl!(Num for f32 f64);
399
400
/// A value bounded by a minimum and a maximum
401
///
402
///  If input is less than min then this returns min.
403
///  If input is greater than max then this returns max.
404
///  Otherwise this returns input.
405
///
406
/// **Panics** in debug mode if `!(min <= max)`.
407
#[inline]
408
0
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
409
0
    debug_assert!(min <= max, "min must be less than or equal to max");
410
0
    if input < min {
411
0
        min
412
0
    } else if input > max {
413
0
        max
414
    } else {
415
0
        input
416
    }
417
0
}
418
419
/// A value bounded by a minimum value
420
///
421
///  If input is less than min then this returns min.
422
///  Otherwise this returns input.
423
///  `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
424
///
425
/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
426
#[inline]
427
0
pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
428
0
    debug_assert!(min == min, "min must not be NAN");
429
0
    if input < min {
430
0
        min
431
    } else {
432
0
        input
433
    }
434
0
}
435
436
/// A value bounded by a maximum value
437
///
438
///  If input is greater than max then this returns max.
439
///  Otherwise this returns input.
440
///  `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
441
///
442
/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
443
#[inline]
444
0
pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
445
0
    debug_assert!(max == max, "max must not be NAN");
446
0
    if input > max {
447
0
        max
448
    } else {
449
0
        input
450
    }
451
0
}
452
453
#[test]
454
fn clamp_test() {
455
    // Int test
456
    assert_eq!(1, clamp(1, -1, 2));
457
    assert_eq!(-1, clamp(-2, -1, 2));
458
    assert_eq!(2, clamp(3, -1, 2));
459
    assert_eq!(1, clamp_min(1, -1));
460
    assert_eq!(-1, clamp_min(-2, -1));
461
    assert_eq!(-1, clamp_max(1, -1));
462
    assert_eq!(-2, clamp_max(-2, -1));
463
464
    // Float test
465
    assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
466
    assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
467
    assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
468
    assert_eq!(1.0, clamp_min(1.0, -1.0));
469
    assert_eq!(-1.0, clamp_min(-2.0, -1.0));
470
    assert_eq!(-1.0, clamp_max(1.0, -1.0));
471
    assert_eq!(-2.0, clamp_max(-2.0, -1.0));
472
    assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
473
    assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
474
    assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
475
}
476
477
#[test]
478
#[should_panic]
479
#[cfg(debug_assertions)]
480
fn clamp_nan_min() {
481
    clamp(0., ::core::f32::NAN, 1.);
482
}
483
484
#[test]
485
#[should_panic]
486
#[cfg(debug_assertions)]
487
fn clamp_nan_max() {
488
    clamp(0., -1., ::core::f32::NAN);
489
}
490
491
#[test]
492
#[should_panic]
493
#[cfg(debug_assertions)]
494
fn clamp_nan_min_max() {
495
    clamp(0., ::core::f32::NAN, ::core::f32::NAN);
496
}
497
498
#[test]
499
#[should_panic]
500
#[cfg(debug_assertions)]
501
fn clamp_min_nan_min() {
502
    clamp_min(0., ::core::f32::NAN);
503
}
504
505
#[test]
506
#[should_panic]
507
#[cfg(debug_assertions)]
508
fn clamp_max_nan_max() {
509
    clamp_max(0., ::core::f32::NAN);
510
}
511
512
#[test]
513
fn from_str_radix_unwrap() {
514
    // The Result error must impl Debug to allow unwrap()
515
516
    let i: i32 = Num::from_str_radix("0", 10).unwrap();
517
    assert_eq!(i, 0);
518
519
    let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
520
    assert_eq!(f, 0.0);
521
}
522
523
#[test]
524
fn from_str_radix_multi_byte_fail() {
525
    // Ensure parsing doesn't panic, even on invalid sign characters
526
    assert!(f32::from_str_radix("™0.2", 10).is_err());
527
528
    // Even when parsing the exponent sign
529
    assert!(f32::from_str_radix("0.2E™1", 10).is_err());
530
}
531
532
#[test]
533
fn from_str_radix_ignore_case() {
534
    assert_eq!(
535
        f32::from_str_radix("InF", 16).unwrap(),
536
        ::core::f32::INFINITY
537
    );
538
    assert_eq!(
539
        f32::from_str_radix("InfinitY", 16).unwrap(),
540
        ::core::f32::INFINITY
541
    );
542
    assert_eq!(
543
        f32::from_str_radix("-InF", 8).unwrap(),
544
        ::core::f32::NEG_INFINITY
545
    );
546
    assert_eq!(
547
        f32::from_str_radix("-InfinitY", 8).unwrap(),
548
        ::core::f32::NEG_INFINITY
549
    );
550
    assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan());
551
    assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan());
552
}
553
554
#[test]
555
fn wrapping_is_num() {
556
    fn require_num<T: Num>(_: &T) {}
557
    require_num(&Wrapping(42_u32));
558
    require_num(&Wrapping(-42));
559
}
560
561
#[test]
562
fn wrapping_from_str_radix() {
563
    macro_rules! test_wrapping_from_str_radix {
564
        ($($t:ty)+) => {
565
            $(
566
                for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
567
                    let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0);
568
                    assert_eq!(w, <$t as Num>::from_str_radix(s, r));
569
                }
570
            )+
571
        };
572
    }
573
574
    test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
575
}
576
577
#[test]
578
fn check_num_ops() {
579
    fn compute<T: Num + Copy>(x: T, y: T) -> T {
580
        x * y / y % y + y - y
581
    }
582
    assert_eq!(compute(1, 2), 1)
583
}
584
585
#[test]
586
fn check_numref_ops() {
587
    fn compute<T: NumRef>(x: T, y: &T) -> T {
588
        x * y / y % y + y - y
589
    }
590
    assert_eq!(compute(1, &2), 1)
591
}
592
593
#[test]
594
fn check_refnum_ops() {
595
    fn compute<T: Copy>(x: &T, y: T) -> T
596
    where
597
        for<'a> &'a T: RefNum<T>,
598
    {
599
        &(&(&(&(x * y) / y) % y) + y) - y
600
    }
601
    assert_eq!(compute(&1, 2), 1)
602
}
603
604
#[test]
605
fn check_refref_ops() {
606
    fn compute<T>(x: &T, y: &T) -> T
607
    where
608
        for<'a> &'a T: RefNum<T>,
609
    {
610
        &(&(&(&(x * y) / y) % y) + y) - y
611
    }
612
    assert_eq!(compute(&1, &2), 1)
613
}
614
615
#[test]
616
fn check_numassign_ops() {
617
    fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
618
        x *= y;
619
        x /= y;
620
        x %= y;
621
        x += y;
622
        x -= y;
623
        x
624
    }
625
    assert_eq!(compute(1, 2), 1)
626
}
627
628
#[cfg(has_int_assignop_ref)]
629
#[test]
630
fn check_numassignref_ops() {
631
    fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {
632
        x *= y;
633
        x /= y;
634
        x %= y;
635
        x += y;
636
        x -= y;
637
        x
638
    }
639
    assert_eq!(compute(1, &2), 1)
640
}