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.31 and greater. |

16 | |

17 | #![doc(html_root_url = "https://docs.rs/num-traits/0.2")] |

18 | #![deny(unconditional_recursion)] |

19 | #![no_std] |

20 | |

21 | // Need to explicitly bring the crate in for inherent float methods |

22 | #[cfg(feature = "std")] |

23 | extern crate std; |

24 | |

25 | use core::fmt; |

26 | use core::num::Wrapping; |

27 | use core::ops::{Add, Div, Mul, Rem, Sub}; |

28 | use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; |

29 | |

30 | pub use crate::bounds::Bounded; |

31 | #[cfg(any(feature = "std", feature = "libm"))] |

32 | pub use crate::float::Float; |

33 | pub use crate::float::FloatConst; |

34 | // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. |

35 | pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; |

36 | pub use crate::identities::{one, zero, One, Zero}; |

37 | pub use crate::int::PrimInt; |

38 | pub use crate::ops::bytes::{FromBytes, ToBytes}; |

39 | pub use crate::ops::checked::{ |

40 | CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, |

41 | }; |

42 | pub use crate::ops::euclid::{CheckedEuclid, Euclid}; |

43 | pub use crate::ops::inv::Inv; |

44 | pub use crate::ops::mul_add::{MulAdd, MulAddAssign}; |

45 | pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; |

46 | pub use crate::ops::wrapping::{ |

47 | WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, |

48 | }; |

49 | pub use crate::pow::{checked_pow, pow, Pow}; |

50 | pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned}; |

51 | |

52 | #[macro_use] |

53 | mod macros; |

54 | |

55 | pub mod bounds; |

56 | pub mod cast; |

57 | pub mod float; |

58 | pub mod identities; |

59 | pub mod int; |

60 | pub mod ops; |

61 | pub mod pow; |

62 | pub mod real; |

63 | pub mod sign; |

64 | |

65 | /// The base trait for numeric types, covering `0` and `1` values, |

66 | /// comparisons, basic numeric operations, and string conversion. |

67 | pub trait Num: PartialEq + Zero + One + NumOps { |

68 | type FromStrRadixErr; |

69 | |

70 | /// Convert from a string and radix (typically `2..=36`). |

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 | /// |

84 | /// # Supported radices |

85 | /// |

86 | /// The exact range of supported radices is at the discretion of each type implementation. For |

87 | /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the |

88 | /// standard library, which **panic** if the radix is not in the range from 2 to 36. The |

89 | /// implementation in this crate for primitive floats is similar. |

90 | /// |

91 | /// For third-party types, it is suggested that implementations should follow suit and at least |

92 | /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix. |

93 | /// It's possible that a type might not even support the common radix 10, nor any, if string |

94 | /// parsing doesn't make sense for that type. |

95 | fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>; |

96 | } |

97 | |

98 | /// Generic trait for types implementing basic numeric operations |

99 | /// |

100 | /// This is automatically implemented for types which implement the operators. |

101 | pub trait NumOps<Rhs = Self, Output = Self>: |

102 | Add<Rhs, Output = Output> |

103 | + Sub<Rhs, Output = Output> |

104 | + Mul<Rhs, Output = Output> |

105 | + Div<Rhs, Output = Output> |

106 | + Rem<Rhs, Output = Output> |

107 | { |

108 | } |

109 | |

110 | impl<T, Rhs, Output> NumOps<Rhs, Output> for T where |

111 | T: Add<Rhs, Output = Output> |

112 | + Sub<Rhs, Output = Output> |

113 | + Mul<Rhs, Output = Output> |

114 | + Div<Rhs, Output = Output> |

115 | + Rem<Rhs, Output = Output> |

116 | { |

117 | } |

118 | |

119 | /// The trait for `Num` types which also implement numeric operations taking |

120 | /// the second operand by reference. |

121 | /// |

122 | /// This is automatically implemented for types which implement the operators. |

123 | pub trait NumRef: Num + for<'r> NumOps<&'r Self> {} |

124 | impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {} |

125 | |

126 | /// The trait for `Num` references which implement numeric operations, taking the |

127 | /// second operand either by value or by reference. |

128 | /// |

129 | /// This is automatically implemented for all types which implement the operators. It covers |

130 | /// every type implementing the operations though, regardless of it being a reference or |

131 | /// related to `Num`. |

132 | pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {} |

133 | impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {} |

134 | |

135 | /// Generic trait for types implementing numeric assignment operators (like `+=`). |

136 | /// |

137 | /// This is automatically implemented for types which implement the operators. |

138 | pub trait NumAssignOps<Rhs = Self>: |

139 | AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs> |

140 | { |

141 | } |

142 | |

143 | impl<T, Rhs> NumAssignOps<Rhs> for T where |

144 | T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs> |

145 | { |

146 | } |

147 | |

148 | /// The trait for `Num` types which also implement assignment operators. |

149 | /// |

150 | /// This is automatically implemented for types which implement the operators. |

151 | pub trait NumAssign: Num + NumAssignOps {} |

152 | impl<T> NumAssign for T where T: Num + NumAssignOps {} |

153 | |

154 | /// The trait for `NumAssign` types which also implement assignment operations |

155 | /// taking the second operand by reference. |

156 | /// |

157 | /// This is automatically implemented for types which implement the operators. |

158 | pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} |

159 | impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {} |

160 | |

161 | macro_rules! int_trait_impl { |

162 | ($name:ident for $($t:ty)*) => ($( |

163 | impl $name for $t { |

164 | type FromStrRadixErr = ::core::num::ParseIntError; |

165 | #[inline] |

166 | fn from_str_radix(s: &str, radix: u32) |

167 | -> Result<Self, ::core::num::ParseIntError> |

168 | { |

169 | <$t>::from_str_radix(s, radix) |

170 | } |

171 | } |

172 | )*) |

173 | } |

174 | int_trait_impl!(Num for usize u8 u16 u32 u64 u128); |

175 | int_trait_impl!(Num for isize i8 i16 i32 i64 i128); |

176 | |

177 | impl<T: Num> Num for Wrapping<T> |

178 | where |

179 | Wrapping<T>: NumOps, |

180 | { |

181 | type FromStrRadixErr = T::FromStrRadixErr; |

182 | fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { |

183 | T::from_str_radix(str, radix).map(Wrapping) |

184 | } |

185 | } |

186 | |

187 | #[derive(Debug)] |

188 | pub enum FloatErrorKind { |

189 | Empty, |

190 | Invalid, |

191 | } |

192 | // FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us, |

193 | // so there's not really any way for us to reuse it. |

194 | #[derive(Debug)] |

195 | pub struct ParseFloatError { |

196 | pub kind: FloatErrorKind, |

197 | } |

198 | |

199 | impl fmt::Display for ParseFloatError { |

200 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |

201 | let description = match self.kind { |

202 | FloatErrorKind::Empty => "cannot parse float from empty string", |

203 | FloatErrorKind::Invalid => "invalid float literal", |

204 | }; |

205 | |

206 | description.fmt(f) |

207 | } |

208 | } |

209 | |

210 | fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool { |

211 | a.len() == b.len() |

212 | && a.bytes().zip(b.bytes()).all(|(a, b)| { |

213 | let a_to_ascii_lower = a | (((b'A'<= a && a <= b'Z') as u8) << 5); |

214 | a_to_ascii_lower == b |

215 | }) |

216 | } |

217 | |

218 | // FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck |

219 | // with this implementation ourselves until we want to make a breaking change. |

220 | // (would have to drop it from `Num` though) |

221 | macro_rules! float_trait_impl { |

222 | ($name:ident for $($t:ident)*) => ($( |

223 | impl $name for $t { |

224 | type FromStrRadixErr = ParseFloatError; |

225 | |

226 | fn from_str_radix(src: &str, radix: u32) |

227 | -> Result<Self, Self::FromStrRadixErr> |

228 | { |

229 | use self::FloatErrorKind::*; |

230 | use self::ParseFloatError as PFE; |

231 | |

232 | // Special case radix 10 to use more accurate standard library implementation |

233 | if radix == 10 { |

234 | return src.parse().map_err(|_| PFE { |

235 | kind: if src.is_empty() { Empty } else { Invalid }, |

236 | }); |

237 | } |

238 | |

239 | // Special values |

240 | if str_to_ascii_lower_eq_str(src, "inf") |

241 | || str_to_ascii_lower_eq_str(src, "infinity") |

242 | { |

243 | return Ok(core::$t::INFINITY); |

244 | } else if str_to_ascii_lower_eq_str(src, "-inf") |

245 | || str_to_ascii_lower_eq_str(src, "-infinity") |

246 | { |

247 | return Ok(core::$t::NEG_INFINITY); |

248 | } else if str_to_ascii_lower_eq_str(src, "nan") { |

249 | return Ok(core::$t::NAN); |

250 | } else if str_to_ascii_lower_eq_str(src, "-nan") { |

251 | return Ok(-core::$t::NAN); |

252 | } |

253 | |

254 | fn slice_shift_char(src: &str) -> Option<(char, &str)> { |

255 | let mut chars = src.chars(); |

256 | Some((chars.next()?, chars.as_str())) |

257 | } |

258 | |

259 | let (is_positive, src) = match slice_shift_char(src) { |

260 | None => return Err(PFE { kind: Empty }), |

261 | Some(('-', "")) => return Err(PFE { kind: Empty }), |

262 | Some(('-', src)) => ( false, src), |

263 | Some((_, _)) => (true, src), |

264 | }; |

265 | |

266 | // The significand to accumulate |

267 | let mut sig = if is_positive { 0.0 } else { -0.0 }; |

268 | // Necessary to detect overflow |

269 | let mut prev_sig = sig; |

270 | let mut cs = src.chars().enumerate(); |

271 | // Exponent prefix and exponent index offset |

272 | let mut exp_info = None::<(char, usize)>; |

273 | |

274 | // Parse the integer part of the significand |

275 | for (i, c) in cs.by_ref() { |

276 | match c.to_digit(radix) { |

277 | Some(digit) => { |

278 | // shift significand one digit left |

279 | sig *= radix as $t; |

280 | |

281 | // add/subtract current digit depending on sign |

282 | if is_positive { |

283 | sig += (digit as isize) as $t; |

284 | } else { |

285 | sig -= (digit as isize) as $t; |

286 | } |

287 | |

288 | // Detect overflow by comparing to last value, except |

289 | // if we've not seen any non-zero digits. |

290 | if prev_sig != 0.0 { |

291 | if is_positive && sig <= prev_sig |

292 | { return Ok(core::$t::INFINITY); } |

293 | if !is_positive && sig >= prev_sig |

294 | { return Ok(core::$t::NEG_INFINITY); } |

295 | |

296 | // Detect overflow by reversing the shift-and-add process |

297 | if is_positive && (prev_sig != (sig - digit as $t) / radix as $t) |

298 | { return Ok(core::$t::INFINITY); } |

299 | if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t) |

300 | { return Ok(core::$t::NEG_INFINITY); } |

301 | } |

302 | prev_sig = sig; |

303 | }, |

304 | None => match c { |

305 | 'e'| 'E'| 'p'| 'P'=> { |

306 | exp_info = Some((c, i + 1)); |

307 | break; // start of exponent |

308 | }, |

309 | '.'=> { |

310 | break; // start of fractional part |

311 | }, |

312 | _ => { |

313 | return Err(PFE { kind: Invalid }); |

314 | }, |

315 | }, |

316 | } |

317 | } |

318 | |

319 | // If we are not yet at the exponent parse the fractional |

320 | // part of the significand |

321 | if exp_info.is_none() { |

322 | let mut power = 1.0; |

323 | for (i, c) in cs.by_ref() { |

324 | match c.to_digit(radix) { |

325 | Some(digit) => { |

326 | // Decrease power one order of magnitude |

327 | power /= radix as $t; |

328 | // add/subtract current digit depending on sign |

329 | sig = if is_positive { |

330 | sig + (digit as $t) * power |

331 | } else { |

332 | sig - (digit as $t) * power |

333 | }; |

334 | // Detect overflow by comparing to last value |

335 | if is_positive && sig < prev_sig |

336 | { return Ok(core::$t::INFINITY); } |

337 | if !is_positive && sig > prev_sig |

338 | { return Ok(core::$t::NEG_INFINITY); } |

339 | prev_sig = sig; |

340 | }, |

341 | None => match c { |

342 | 'e'| 'E'| 'p'| 'P'=> { |

343 | exp_info = Some((c, i + 1)); |

344 | break; // start of exponent |

345 | }, |

346 | _ => { |

347 | return Err(PFE { kind: Invalid }); |

348 | }, |

349 | }, |

350 | } |

351 | } |

352 | } |

353 | |

354 | // Parse and calculate the exponent |

355 | let exp = match exp_info { |

356 | Some((c, offset)) => { |

357 | let base = match c { |

358 | 'E'| 'e' if radix == 10 => 10.0, |

359 | 'P'| 'p' if radix == 16 => 2.0, |

360 | _ => return Err(PFE { kind: Invalid }), |

361 | }; |

362 | |

363 | // Parse the exponent as decimal integer |

364 | let src = &src[offset..]; |

365 | let (is_positive, exp) = match slice_shift_char(src) { |

366 | Some(('-', src)) => ( false, src.parse::<usize>()), |

367 | Some(('+', src)) => ( true, src.parse::<usize>()), |

368 | Some((_, _)) => (true, src.parse::<usize>()), |

369 | None => return Err(PFE { kind: Invalid }), |

370 | }; |

371 | |

372 | #[cfg(feature = "std")] |

373 | fn pow(base: $t, exp: usize) -> $t { |

374 | Float::powi(base, exp as i32) |

375 | } |

376 | // otherwise uses the generic `pow` from the root |

377 | |

378 | match (is_positive, exp) { |

379 | (true, Ok(exp)) => pow(base, exp), |

380 | (false, Ok(exp)) => 1.0 / pow(base, exp), |

381 | (_, Err(_)) => return Err(PFE { kind: Invalid }), |

382 | } |

383 | }, |

384 | None => 1.0, // no exponent |

385 | }; |

386 | |

387 | Ok(sig * exp) |

388 | } |

389 | } |

390 | )*) |

391 | } |

392 | float_trait_impl!(Num for f32 f64); |

393 | |

394 | /// A value bounded by a minimum and a maximum |

395 | /// |

396 | /// If input is less than min then this returns min. |

397 | /// If input is greater than max then this returns max. |

398 | /// Otherwise this returns input. |

399 | /// |

400 | /// **Panics** in debug mode if `!(min <= max)`. |

401 | #[inline] |

402 | pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T { |

403 | debug_assert!(min <= max, "min must be less than or equal to max"); |

404 | if input < min { |

405 | min |

406 | } else if input > max { |

407 | max |

408 | } else { |

409 | input |

410 | } |

411 | } |

412 | |

413 | /// A value bounded by a minimum value |

414 | /// |

415 | /// If input is less than min then this returns min. |

416 | /// Otherwise this returns input. |

417 | /// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`. |

418 | /// |

419 | /// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.) |

420 | #[inline] |

421 | #[allow(clippy::eq_op)] |

422 | pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T { |

423 | debug_assert!(min == min, "min must not be NAN"); |

424 | if input < min { |

425 | min |

426 | } else { |

427 | input |

428 | } |

429 | } |

430 | |

431 | /// A value bounded by a maximum value |

432 | /// |

433 | /// If input is greater than max then this returns max. |

434 | /// Otherwise this returns input. |

435 | /// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`. |

436 | /// |

437 | /// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.) |

438 | #[inline] |

439 | #[allow(clippy::eq_op)] |

440 | pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T { |

441 | debug_assert!(max == max, "max must not be NAN"); |

442 | if input > max { |

443 | max |

444 | } else { |

445 | input |

446 | } |

447 | } |

448 | |

449 | #[test] |

450 | fn clamp_test() { |

451 | // Int test |

452 | assert_eq!(1, clamp(1, -1, 2)); |

453 | assert_eq!(-1, clamp(-2, -1, 2)); |

454 | assert_eq!(2, clamp(3, -1, 2)); |

455 | assert_eq!(1, clamp_min(1, -1)); |

456 | assert_eq!(-1, clamp_min(-2, -1)); |

457 | assert_eq!(-1, clamp_max(1, -1)); |

458 | assert_eq!(-2, clamp_max(-2, -1)); |

459 | |

460 | // Float test |

461 | assert_eq!(1.0, clamp(1.0, -1.0, 2.0)); |

462 | assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0)); |

463 | assert_eq!(2.0, clamp(3.0, -1.0, 2.0)); |

464 | assert_eq!(1.0, clamp_min(1.0, -1.0)); |

465 | assert_eq!(-1.0, clamp_min(-2.0, -1.0)); |

466 | assert_eq!(-1.0, clamp_max(1.0, -1.0)); |

467 | assert_eq!(-2.0, clamp_max(-2.0, -1.0)); |

468 | assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan()); |

469 | assert!(clamp_min(::core::f32::NAN, 1.0).is_nan()); |

470 | assert!(clamp_max(::core::f32::NAN, 1.0).is_nan()); |

471 | } |

472 | |

473 | #[test] |

474 | #[should_panic] |

475 | #[cfg(debug_assertions)] |

476 | fn clamp_nan_min() { |

477 | clamp(0., ::core::f32::NAN, 1.); |

478 | } |

479 | |

480 | #[test] |

481 | #[should_panic] |

482 | #[cfg(debug_assertions)] |

483 | fn clamp_nan_max() { |

484 | clamp(0., -1., ::core::f32::NAN); |

485 | } |

486 | |

487 | #[test] |

488 | #[should_panic] |

489 | #[cfg(debug_assertions)] |

490 | fn clamp_nan_min_max() { |

491 | clamp(0., ::core::f32::NAN, ::core::f32::NAN); |

492 | } |

493 | |

494 | #[test] |

495 | #[should_panic] |

496 | #[cfg(debug_assertions)] |

497 | fn clamp_min_nan_min() { |

498 | clamp_min(0., ::core::f32::NAN); |

499 | } |

500 | |

501 | #[test] |

502 | #[should_panic] |

503 | #[cfg(debug_assertions)] |

504 | fn clamp_max_nan_max() { |

505 | clamp_max(0., ::core::f32::NAN); |

506 | } |

507 | |

508 | #[test] |

509 | fn from_str_radix_unwrap() { |

510 | // The Result error must impl Debug to allow unwrap() |

511 | |

512 | let i: i32 = Num::from_str_radix("0", 10).unwrap(); |

513 | assert_eq!(i, 0); |

514 | |

515 | let f: f32 = Num::from_str_radix("0.0", 10).unwrap(); |

516 | assert_eq!(f, 0.0); |

517 | } |

518 | |

519 | #[test] |

520 | fn from_str_radix_multi_byte_fail() { |

521 | // Ensure parsing doesn't panic, even on invalid sign characters |

522 | assert!(f32::from_str_radix("™0.2", 10).is_err()); |

523 | |

524 | // Even when parsing the exponent sign |

525 | assert!(f32::from_str_radix("0.2E™1", 10).is_err()); |

526 | } |

527 | |

528 | #[test] |

529 | fn from_str_radix_ignore_case() { |

530 | assert_eq!( |

531 | f32::from_str_radix("InF", 16).unwrap(), |

532 | ::core::f32::INFINITY |

533 | ); |

534 | assert_eq!( |

535 | f32::from_str_radix("InfinitY", 16).unwrap(), |

536 | ::core::f32::INFINITY |

537 | ); |

538 | assert_eq!( |

539 | f32::from_str_radix("-InF", 8).unwrap(), |

540 | ::core::f32::NEG_INFINITY |

541 | ); |

542 | assert_eq!( |

543 | f32::from_str_radix("-InfinitY", 8).unwrap(), |

544 | ::core::f32::NEG_INFINITY |

545 | ); |

546 | assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan()); |

547 | assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan()); |

548 | } |

549 | |

550 | #[test] |

551 | fn wrapping_is_num() { |

552 | fn require_num<T: Num>(_: &T) {} |

553 | require_num(&Wrapping(42_u32)); |

554 | require_num(&Wrapping(-42)); |

555 | } |

556 | |

557 | #[test] |

558 | fn wrapping_from_str_radix() { |

559 | macro_rules! test_wrapping_from_str_radix { |

560 | ($($t:ty)+) => { |

561 | $( |

562 | for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] { |

563 | let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0); |

564 | assert_eq!(w, <$t as Num>::from_str_radix(s, r)); |

565 | } |

566 | )+ |

567 | }; |

568 | } |

569 | |

570 | test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); |

571 | } |

572 | |

573 | #[test] |

574 | fn check_num_ops() { |

575 | fn compute<T: Num + Copy>(x: T, y: T) -> T { |

576 | x * y / y % y + y - y |

577 | } |

578 | assert_eq!(compute(1, 2), 1) |

579 | } |

580 | |

581 | #[test] |

582 | fn check_numref_ops() { |

583 | fn compute<T: NumRef>(x: T, y: &T) -> T { |

584 | x * y / y % y + y - y |

585 | } |

586 | assert_eq!(compute(1, &2), 1) |

587 | } |

588 | |

589 | #[test] |

590 | fn check_refnum_ops() { |

591 | fn compute<T: Copy>(x: &T, y: T) -> T |

592 | where |

593 | for<'a> &'a T: RefNum<T>, |

594 | { |

595 | &(&(&(&(x * y) / y) % y) + y) - y |

596 | } |

597 | assert_eq!(compute(&1, 2), 1) |

598 | } |

599 | |

600 | #[test] |

601 | fn check_refref_ops() { |

602 | fn compute<T>(x: &T, y: &T) -> T |

603 | where |

604 | for<'a> &'a T: RefNum<T>, |

605 | { |

606 | &(&(&(&(x * y) / y) % y) + y) - y |

607 | } |

608 | assert_eq!(compute(&1, &2), 1) |

609 | } |

610 | |

611 | #[test] |

612 | fn check_numassign_ops() { |

613 | fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T { |

614 | x *= y; |

615 | x /= y; |

616 | x %= y; |

617 | x += y; |

618 | x -= y; |

619 | x |

620 | } |

621 | assert_eq!(compute(1, 2), 1) |

622 | } |

623 | |

624 | #[test] |

625 | fn check_numassignref_ops() { |

626 | fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T { |

627 | x *= y; |

628 | x /= y; |

629 | x %= y; |

630 | x += y; |

631 | x -= y; |

632 | x |

633 | } |

634 | assert_eq!(compute(1, &2), 1) |

635 | } |

636 |