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.60 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, ConstOne, ConstZero, 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.
from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>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;
from_str_radix(str: &str, radix: u32) -> Result<Self, Self::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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result200     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 
str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool210 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]
clamp<T: PartialOrd>(input: T, min: T, max: T) -> T402 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)]
clamp_min<T: PartialOrd>(input: T, min: T) -> T422 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)]
clamp_max<T: PartialOrd>(input: T, max: T) -> T440 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]
clamp_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)]
clamp_nan_min()476 fn clamp_nan_min() {
477     clamp(0., ::core::f32::NAN, 1.);
478 }
479 
480 #[test]
481 #[should_panic]
482 #[cfg(debug_assertions)]
clamp_nan_max()483 fn clamp_nan_max() {
484     clamp(0., -1., ::core::f32::NAN);
485 }
486 
487 #[test]
488 #[should_panic]
489 #[cfg(debug_assertions)]
clamp_nan_min_max()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)]
clamp_min_nan_min()497 fn clamp_min_nan_min() {
498     clamp_min(0., ::core::f32::NAN);
499 }
500 
501 #[test]
502 #[should_panic]
503 #[cfg(debug_assertions)]
clamp_max_nan_max()504 fn clamp_max_nan_max() {
505     clamp_max(0., ::core::f32::NAN);
506 }
507 
508 #[test]
from_str_radix_unwrap()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]
from_str_radix_multi_byte_fail()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]
from_str_radix_ignore_case()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]
wrapping_is_num()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]
wrapping_from_str_radix()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]
check_num_ops()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]
check_numref_ops()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]
check_refnum_ops()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]
check_refref_ops()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]
check_numassign_ops()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]
check_numassignref_ops()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