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