1use crate::{udouble, ModularInteger, ModularUnaryOps, Reducer};
2use core::ops::*;
3#[cfg(feature = "num-traits")]
4use num_traits::{Inv, Pow};
5
6#[derive(Debug, Clone, Copy)]
8pub struct ReducedInt<T, R: Reducer<T>> {
9 a: T,
11
12 r: R,
14}
15
16impl<T, R: Reducer<T>> ReducedInt<T, R> {
17 #[inline]
19 pub fn new(n: T, m: &T) -> Self {
20 let r = R::new(m);
21 let a = r.transform(n);
22 Self { a, r }
23 }
24
25 #[inline(always)]
26 fn check_modulus_eq(&self, rhs: &Self)
27 where
28 T: PartialEq,
29 {
30 if cfg!(debug_assertions) && self.r.modulus() != rhs.r.modulus() {
32 panic!("The modulus of two operators should be the same!");
33 }
34 }
35
36 #[inline(always)]
37 pub fn repr(&self) -> &T {
38 &self.a
39 }
40
41 #[inline(always)]
42 pub fn inv(self) -> Option<Self> {
43 Some(Self {
44 a: self.r.inv(self.a)?,
45 r: self.r,
46 })
47 }
48
49 #[inline(always)]
50 pub fn pow(self, exp: &T) -> Self {
51 Self {
52 a: self.r.pow(self.a, exp),
53 r: self.r,
54 }
55 }
56}
57
58impl<T: PartialEq, R: Reducer<T>> PartialEq for ReducedInt<T, R> {
59 #[inline]
60 fn eq(&self, other: &Self) -> bool {
61 self.check_modulus_eq(other);
62 self.a == other.a
63 }
64}
65
66macro_rules! impl_binops {
67 ($method:ident, impl $op:ident) => {
68 impl<T: PartialEq, R: Reducer<T>> $op for ReducedInt<T, R> {
69 type Output = Self;
70 fn $method(self, rhs: Self) -> Self::Output {
71 self.check_modulus_eq(&rhs);
72 let Self { a, r } = self;
73 let a = r.$method(&a, &rhs.a);
74 Self { a, r }
75 }
76 }
77
78 impl<T: PartialEq + Clone, R: Reducer<T>> $op<&Self> for ReducedInt<T, R> {
79 type Output = Self;
80 #[inline]
81 fn $method(self, rhs: &Self) -> Self::Output {
82 self.check_modulus_eq(&rhs);
83 let Self { a, r } = self;
84 let a = r.$method(&a, &rhs.a);
85 Self { a, r }
86 }
87 }
88
89 impl<T: PartialEq + Clone, R: Reducer<T>> $op<ReducedInt<T, R>> for &ReducedInt<T, R> {
90 type Output = ReducedInt<T, R>;
91 #[inline]
92 fn $method(self, rhs: ReducedInt<T, R>) -> Self::Output {
93 self.check_modulus_eq(&rhs);
94 let ReducedInt { a, r } = rhs;
95 let a = r.$method(&self.a, &a);
96 ReducedInt { a, r }
97 }
98 }
99
100 impl<T: PartialEq + Clone, R: Reducer<T> + Clone> $op<&ReducedInt<T, R>>
101 for &ReducedInt<T, R>
102 {
103 type Output = ReducedInt<T, R>;
104 #[inline]
105 fn $method(self, rhs: &ReducedInt<T, R>) -> Self::Output {
106 self.check_modulus_eq(&rhs);
107 let a = self.r.$method(&self.a, &rhs.a);
108 ReducedInt {
109 a,
110 r: self.r.clone(),
111 }
112 }
113 }
114
115 impl<T, R: Reducer<T>> $op<T> for ReducedInt<T, R> {
116 type Output = Self;
117 #[inline]
118 fn $method(self, rhs: T) -> Self::Output {
119 let Self { a, r } = self;
120 let rhs = r.transform(rhs);
121 let a = r.$method(&a, &rhs);
122 Self { a, r }
123 }
124 }
125
126 impl<T: PartialEq + Clone, R: Reducer<T>> $op<&T> for ReducedInt<T, R> {
127 type Output = Self;
128 #[inline]
129 fn $method(self, rhs: &T) -> Self::Output {
130 let Self { a, r } = self;
131 let rhs = r.transform(rhs.clone());
132 let a = r.$method(&a, &rhs);
133 Self { a, r }
134 }
135 }
136
137 impl<T, R: Reducer<T> + Clone> $op<T> for &ReducedInt<T, R> {
138 type Output = ReducedInt<T, R>;
139 #[inline]
140 fn $method(self, rhs: T) -> Self::Output {
141 let rhs = self.r.transform(rhs);
142 let a = self.r.$method(&self.a, &rhs);
143 ReducedInt {
144 a,
145 r: self.r.clone(),
146 }
147 }
148 }
149
150 impl<T: PartialEq + Clone, R: Reducer<T> + Clone> $op<&T> for &ReducedInt<T, R> {
151 type Output = ReducedInt<T, R>;
152 #[inline]
153 fn $method(self, rhs: &T) -> Self::Output {
154 let rhs = self.r.transform(rhs.clone());
155 let a = self.r.$method(&self.a, &rhs);
156 ReducedInt {
157 a,
158 r: self.r.clone(),
159 }
160 }
161 }
162 };
163}
164impl_binops!(add, impl Add);
165impl_binops!(sub, impl Sub);
166impl_binops!(mul, impl Mul);
167
168macro_rules! impl_assign_ops {
169 ($method:ident, impl $op:ident, with $reducer_method:ident) => {
170 impl<T: PartialEq, R: Reducer<T>> $op for ReducedInt<T, R> {
171 #[inline]
172 fn $method(&mut self, rhs: Self) {
173 self.check_modulus_eq(&rhs);
174 let Self { a, r } = self;
175 r.$reducer_method(a, &rhs.a);
176 }
177 }
178
179 impl<T: PartialEq, R: Reducer<T>> $op<&Self> for ReducedInt<T, R> {
180 #[inline]
181 fn $method(&mut self, rhs: &Self) {
182 self.check_modulus_eq(rhs);
183 let Self { a, r } = self;
184 r.$reducer_method(a, &rhs.a);
185 }
186 }
187
188 impl<T, R: Reducer<T>> $op<T> for ReducedInt<T, R> {
189 #[inline]
190 fn $method(&mut self, rhs: T) {
191 let Self { a, r } = self;
192 let rhs = r.transform(rhs);
193 r.$reducer_method(a, &rhs);
194 }
195 }
196
197 impl<T: PartialEq + Clone, R: Reducer<T>> $op<&T> for ReducedInt<T, R> {
198 #[inline]
199 fn $method(&mut self, rhs: &T) {
200 let Self { a, r } = self;
201 let rhs = r.transform(rhs.clone());
202 r.$reducer_method(a, &rhs);
203 }
204 }
205 };
206}
207impl_assign_ops!(add_assign, impl AddAssign, with add_in_place);
208impl_assign_ops!(sub_assign, impl SubAssign, with sub_in_place);
209impl_assign_ops!(mul_assign, impl MulAssign, with mul_in_place);
210
211impl<T: PartialEq, R: Reducer<T>> Neg for ReducedInt<T, R> {
212 type Output = Self;
213 #[inline]
214 fn neg(self) -> Self::Output {
215 let Self { a, r } = self;
216 let a = r.neg(a);
217 Self { a, r }
218 }
219}
220impl<T: PartialEq + Clone, R: Reducer<T> + Clone> Neg for &ReducedInt<T, R> {
221 type Output = ReducedInt<T, R>;
222 #[inline]
223 fn neg(self) -> Self::Output {
224 let a = self.r.neg(self.a.clone());
225 ReducedInt {
226 a,
227 r: self.r.clone(),
228 }
229 }
230}
231
232const INV_ERR_MSG: &str = "the modular inverse doesn't exist!";
233
234#[cfg(feature = "num-traits")]
235impl<T: PartialEq, R: Reducer<T>> Inv for ReducedInt<T, R> {
236 type Output = Self;
237 #[inline]
238 fn inv(self) -> Self::Output {
239 self.inv().expect(INV_ERR_MSG)
240 }
241}
242#[cfg(feature = "num-traits")]
243impl<T: PartialEq + Clone, R: Reducer<T> + Clone> Inv for &ReducedInt<T, R> {
244 type Output = ReducedInt<T, R>;
245 #[inline]
246 fn inv(self) -> Self::Output {
247 self.clone().inv().expect(INV_ERR_MSG)
248 }
249}
250
251impl<T: PartialEq, R: Reducer<T>> Div for ReducedInt<T, R> {
252 type Output = Self;
253 #[inline]
254 fn div(self, rhs: Self) -> Self::Output {
255 self.check_modulus_eq(&rhs);
256 let ReducedInt { a, r } = rhs;
257 let a = r.mul(&self.a, &r.inv(a).expect(INV_ERR_MSG));
258 ReducedInt { a, r }
259 }
260}
261impl<T: PartialEq + Clone, R: Reducer<T>> Div<&ReducedInt<T, R>> for ReducedInt<T, R> {
262 type Output = Self;
263 #[inline]
264 fn div(self, rhs: &Self) -> Self::Output {
265 self.check_modulus_eq(rhs);
266 let Self { a, r } = self;
267 let a = r.mul(&a, &r.inv(rhs.a.clone()).expect(INV_ERR_MSG));
268 ReducedInt { a, r }
269 }
270}
271impl<T: PartialEq + Clone, R: Reducer<T>> Div<ReducedInt<T, R>> for &ReducedInt<T, R> {
272 type Output = ReducedInt<T, R>;
273 #[inline]
274 fn div(self, rhs: ReducedInt<T, R>) -> Self::Output {
275 self.check_modulus_eq(&rhs);
276 let ReducedInt { a, r } = rhs;
277 let a = r.mul(&self.a, &r.inv(a).expect(INV_ERR_MSG));
278 ReducedInt { a, r }
279 }
280}
281impl<T: PartialEq + Clone, R: Reducer<T> + Clone> Div<&ReducedInt<T, R>> for &ReducedInt<T, R> {
282 type Output = ReducedInt<T, R>;
283 #[inline]
284 fn div(self, rhs: &ReducedInt<T, R>) -> Self::Output {
285 self.check_modulus_eq(rhs);
286 let a = self
287 .r
288 .mul(&self.a, &self.r.inv(rhs.a.clone()).expect(INV_ERR_MSG));
289 ReducedInt {
290 a,
291 r: self.r.clone(),
292 }
293 }
294}
295
296#[cfg(feature = "num-traits")]
297impl<T: PartialEq, R: Reducer<T>> Pow<T> for ReducedInt<T, R> {
298 type Output = Self;
299 #[inline]
300 fn pow(self, rhs: T) -> Self::Output {
301 ReducedInt::pow(self, &rhs)
302 }
303}
304#[cfg(feature = "num-traits")]
305impl<T: PartialEq + Clone, R: Reducer<T> + Clone> Pow<T> for &ReducedInt<T, R> {
306 type Output = ReducedInt<T, R>;
307 #[inline]
308 fn pow(self, rhs: T) -> Self::Output {
309 let a = self.r.pow(self.a.clone(), &rhs);
310 ReducedInt {
311 a,
312 r: self.r.clone(),
313 }
314 }
315}
316
317impl<T: PartialEq + Clone, R: Reducer<T> + Clone> ModularInteger for ReducedInt<T, R> {
318 type Base = T;
319
320 #[inline]
321 fn modulus(&self) -> T {
322 self.r.modulus()
323 }
324
325 #[inline(always)]
326 fn residue(&self) -> T {
327 debug_assert!(self.r.check(&self.a));
328 self.r.residue(self.a.clone())
329 }
330
331 #[inline(always)]
332 fn is_zero(&self) -> bool {
333 self.r.is_zero(&self.a)
334 }
335
336 #[inline]
337 fn convert(&self, n: T) -> Self {
338 Self {
339 a: self.r.transform(n),
340 r: self.r.clone(),
341 }
342 }
343
344 #[inline]
345 fn double(self) -> Self {
346 let Self { a, r } = self;
347 let a = r.dbl(a);
348 Self { a, r }
349 }
350
351 #[inline]
352 fn square(self) -> Self {
353 let Self { a, r } = self;
354 let a = r.sqr(a);
355 Self { a, r }
356 }
357}
358
359#[derive(Debug, Clone, Copy)]
363pub struct Vanilla<T>(T);
364
365macro_rules! impl_uprim_vanilla_core_const {
366 ($($T:ty)*) => {$(
367 impl Vanilla<$T> {
369 #[inline]
370 pub(crate) const fn add(m: &$T, lhs: $T, rhs: $T) -> $T {
371 let (sum, overflow) = lhs.overflowing_add(rhs);
372 if overflow || sum >= *m {
373 let (sum2, overflow2) = sum.overflowing_sub(*m);
374 debug_assert!(overflow == overflow2);
375 sum2
376 } else {
377 sum
378 }
379 }
380
381 #[inline]
382 pub(crate) const fn dbl(m: &$T, target: $T) -> $T {
383 Self::add(m, target, target)
384 }
385
386 #[inline]
387 pub(crate) const fn sub(m: &$T, lhs: $T, rhs: $T) -> $T {
388 if lhs >= rhs {
390 lhs - rhs
391 } else {
392 *m - (rhs - lhs)
393 }
394 }
395
396 #[inline]
397 pub(crate) const fn neg(m: &$T, target: $T) -> $T {
398 match target {
399 0 => 0,
400 x => *m - x
401 }
402 }
403 }
404 )*};
405}
406impl_uprim_vanilla_core_const!(u8 u16 u32 u64 u128 usize);
407
408macro_rules! impl_reduced_binary_pow {
409 ($T:ty) => {
410 fn pow(&self, base: $T, exp: &$T) -> $T {
411 match *exp {
412 1 => base,
413 2 => self.sqr(base),
414 e => {
415 let mut multi = base;
416 let mut exp = e;
417 let mut result = self.transform(1);
418 while exp > 0 {
419 if exp & 1 != 0 {
420 result = self.mul(&result, &multi);
421 }
422 multi = self.sqr(multi);
423 exp >>= 1;
424 }
425 result
426 }
427 }
428 }
429 };
430}
431
432pub(crate) use impl_reduced_binary_pow;
433
434macro_rules! impl_uprim_vanilla_core {
435 ($single:ty) => {
436 #[inline(always)]
437 fn new(m: &$single) -> Self {
438 assert!(m > &0);
439 Self(*m)
440 }
441 #[inline(always)]
442 fn transform(&self, target: $single) -> $single {
443 target % self.0
444 }
445 #[inline(always)]
446 fn check(&self, target: &$single) -> bool {
447 *target < self.0
448 }
449 #[inline(always)]
450 fn residue(&self, target: $single) -> $single {
451 target
452 }
453 #[inline(always)]
454 fn modulus(&self) -> $single {
455 self.0
456 }
457 #[inline(always)]
458 fn is_zero(&self, target: &$single) -> bool {
459 *target == 0
460 }
461
462 #[inline(always)]
463 fn add(&self, lhs: &$single, rhs: &$single) -> $single {
464 Vanilla::<$single>::add(&self.0, *lhs, *rhs)
465 }
466
467 #[inline(always)]
468 fn dbl(&self, target: $single) -> $single {
469 Vanilla::<$single>::dbl(&self.0, target)
470 }
471
472 #[inline(always)]
473 fn sub(&self, lhs: &$single, rhs: &$single) -> $single {
474 Vanilla::<$single>::sub(&self.0, *lhs, *rhs)
475 }
476
477 #[inline(always)]
478 fn neg(&self, target: $single) -> $single {
479 Vanilla::<$single>::neg(&self.0, target)
480 }
481
482 #[inline(always)]
483 fn inv(&self, target: $single) -> Option<$single> {
484 target.invm(&self.0)
485 }
486
487 impl_reduced_binary_pow!($single);
488 };
489}
490
491macro_rules! impl_uprim_vanilla {
492 ($t:ident, $ns:ident) => {
493 mod $ns {
494 use super::*;
495 use crate::word::$t::*;
496
497 impl Reducer<$t> for Vanilla<$t> {
498 impl_uprim_vanilla_core!($t);
499
500 #[inline]
501 fn mul(&self, lhs: &$t, rhs: &$t) -> $t {
502 (wmul(*lhs, *rhs) % extend(self.0)) as $t
503 }
504
505 #[inline]
506 fn sqr(&self, target: $t) -> $t {
507 (wsqr(target) % extend(self.0)) as $t
508 }
509 }
510 }
511 };
512}
513
514impl_uprim_vanilla!(u8, u8_impl);
515impl_uprim_vanilla!(u16, u16_impl);
516impl_uprim_vanilla!(u32, u32_impl);
517impl_uprim_vanilla!(u64, u64_impl);
518impl_uprim_vanilla!(usize, usize_impl);
519
520impl Reducer<u128> for Vanilla<u128> {
521 impl_uprim_vanilla_core!(u128);
522
523 #[inline]
524 fn mul(&self, lhs: &u128, rhs: &u128) -> u128 {
525 udouble::widening_mul(*lhs, *rhs) % self.0
526 }
527
528 #[inline]
529 fn sqr(&self, target: u128) -> u128 {
530 udouble::widening_square(target) % self.0
531 }
532}
533
534#[cfg(all(feature = "num-bigint", feature = "num-traits"))]
535mod bigint_impl {
536 use super::*;
537 use crate::ModularCoreOps;
538 use crate::ModularPow;
539 use num_bigint::BigUint;
540 use num_traits::Zero;
541
542 impl Reducer<BigUint> for Vanilla<BigUint> {
543 #[inline]
544 fn new(m: &BigUint) -> Self {
545 assert!(!m.is_zero());
546 Self(m.clone())
547 }
548
549 #[inline]
550 fn transform(&self, target: BigUint) -> BigUint {
551 target % &self.0
552 }
553
554 #[inline]
555 fn check(&self, target: &BigUint) -> bool {
556 target < &self.0
557 }
558
559 #[inline]
560 fn modulus(&self) -> BigUint {
561 self.0.clone()
562 }
563
564 #[inline]
565 fn residue(&self, target: BigUint) -> BigUint {
566 target
567 }
568
569 #[inline]
570 fn is_zero(&self, target: &BigUint) -> bool {
571 target.is_zero()
572 }
573
574 #[inline]
575 fn add(&self, lhs: &BigUint, rhs: &BigUint) -> BigUint {
576 lhs.addm(rhs, &self.0)
577 }
578
579 #[inline]
580 fn dbl(&self, target: BigUint) -> BigUint {
581 target.dblm(&self.0)
582 }
583
584 #[inline]
585 fn sub(&self, lhs: &BigUint, rhs: &BigUint) -> BigUint {
586 lhs.subm(rhs, &self.0)
587 }
588
589 #[inline]
590 fn neg(&self, target: BigUint) -> BigUint {
591 target.negm(&self.0)
592 }
593
594 #[inline]
595 fn mul(&self, lhs: &BigUint, rhs: &BigUint) -> BigUint {
596 lhs.mulm(rhs, &self.0)
597 }
598
599 #[inline]
600 fn inv(&self, target: BigUint) -> Option<BigUint> {
601 target.invm(&self.0)
602 }
603
604 #[inline]
605 fn sqr(&self, target: BigUint) -> BigUint {
606 target.sqm(&self.0)
607 }
608
609 #[inline]
610 fn pow(&self, base: BigUint, exp: &BigUint) -> BigUint {
611 base.powm(exp, &self.0)
612 }
613 }
614}
615
616pub type VanillaInt<T> = ReducedInt<T, Vanilla<T>>;
618
619#[cfg(test)]
620pub(crate) mod tests {
621 use super::*;
622 use crate::{ModularCoreOps, ModularPow, ModularUnaryOps};
623 use core::marker::PhantomData;
624 use rand::random;
625
626 pub(crate) struct ReducedTester<T>(PhantomData<T>);
627
628 macro_rules! impl_reduced_test_for {
629 ($($T:ty)*) => {$(
630 impl ReducedTester<$T> {
631 pub fn test_against_modops<R: Reducer<$T> + Copy>(random_mode: i32) {
636 let m = match random_mode {
637 0 => random::<$T>().saturating_add(1),
638 1 => random::<$T>().saturating_add(1) | 1,
639 2 => random::<$T>().saturating_add(1 << (<$T>::BITS / 2)),
640 _ => unreachable!()
641 };
642
643 let (a, b) = (random::<$T>(), random::<$T>());
644 let am = ReducedInt::<$T, R>::new(a, &m);
645 let bm = ReducedInt::<$T, R>::new(b, &m);
646 assert_eq!((am + bm).residue(), a.addm(b, &m), "incorrect add");
647 assert_eq!((am - bm).residue(), a.subm(b, &m), "incorrect sub");
648 assert_eq!((am * bm).residue(), a.mulm(b, &m), "incorrect mul");
649 assert_eq!(am.neg().residue(), a.negm(&m), "incorrect neg");
650 assert_eq!(am.double().residue(), a.dblm(&m), "incorrect dbl");
651 assert_eq!(am.square().residue(), a.sqm(&m), "incorrect sqr");
652
653 let e = random::<u8>() as $T;
654 assert_eq!(am.pow(&e).residue(), a.powm(e, &m), "incorrect pow");
655 if let Some(v) = a.invm(&m) {
656 assert_eq!(am.inv().unwrap().residue(), v, "incorrect inv");
657 }
658
659 assert_eq!((am + &b).residue(), a.addm(b, &m), "incorrect add<&T>");
662 assert_eq!((am - &b).residue(), a.subm(b, &m), "incorrect sub<&T>");
663 assert_eq!((am * &b).residue(), a.mulm(b, &m), "incorrect mul<&T>");
664 assert_eq!((&am + a).residue(), a.addm(a, &m), "incorrect &add<T>");
666 assert_eq!((&am - a).residue(), a.subm(a, &m), "incorrect &sub<T>");
667 assert_eq!((&am * a).residue(), a.mulm(a, &m), "incorrect &mul<T>");
668 assert_eq!((&am + &b).residue(), a.addm(b, &m), "incorrect &add<&T>");
670 assert_eq!((&am - &b).residue(), a.subm(b, &m), "incorrect &sub<&T>");
671 assert_eq!((&am * &b).residue(), a.mulm(b, &m), "incorrect &mul<&T>");
672
673 let mut tmp;
675 tmp = am;
676 tmp += bm;
677 assert_eq!(tmp.residue(), a.addm(b, &m), "incorrect add_assign<Self>");
678 tmp = am;
679 tmp += &bm;
680 assert_eq!(tmp.residue(), a.addm(b, &m), "incorrect add_assign<&Self>");
681 tmp = am;
682 tmp += b;
683 assert_eq!(tmp.residue(), a.addm(b, &m), "incorrect add_assign<T>");
684 tmp = am;
685 tmp += &b;
686 assert_eq!(tmp.residue(), a.addm(b, &m), "incorrect add_assign<&T>");
687
688 tmp = am;
689 tmp -= bm;
690 assert_eq!(tmp.residue(), a.subm(b, &m), "incorrect sub_assign<Self>");
691 tmp = am;
692 tmp -= &bm;
693 assert_eq!(tmp.residue(), a.subm(b, &m), "incorrect sub_assign<&Self>");
694 tmp = am;
695 tmp -= b;
696 assert_eq!(tmp.residue(), a.subm(b, &m), "incorrect sub_assign<T>");
697 tmp = am;
698 tmp -= &b;
699 assert_eq!(tmp.residue(), a.subm(b, &m), "incorrect sub_assign<&T>");
700
701 tmp = am;
702 tmp *= bm;
703 assert_eq!(tmp.residue(), a.mulm(b, &m), "incorrect mul_assign<Self>");
704 tmp = am;
705 tmp *= &bm;
706 assert_eq!(tmp.residue(), a.mulm(b, &m), "incorrect mul_assign<&Self>");
707 tmp = am;
708 tmp *= b;
709 assert_eq!(tmp.residue(), a.mulm(b, &m), "incorrect mul_assign<T>");
710 tmp = am;
711 tmp *= &b;
712 assert_eq!(tmp.residue(), a.mulm(b, &m), "incorrect mul_assign<&T>");
713 }
714 }
715 )*};
716 }
717 impl_reduced_test_for!(u8 u16 u32 u64 u128 usize);
718
719 #[test]
720 fn test_against_modops() {
721 for _ in 0..10 {
722 ReducedTester::<u8>::test_against_modops::<Vanilla<u8>>(0);
723 ReducedTester::<u16>::test_against_modops::<Vanilla<u16>>(0);
724 ReducedTester::<u32>::test_against_modops::<Vanilla<u32>>(0);
725 ReducedTester::<u64>::test_against_modops::<Vanilla<u64>>(0);
726 ReducedTester::<u128>::test_against_modops::<Vanilla<u128>>(0);
727 ReducedTester::<usize>::test_against_modops::<Vanilla<usize>>(0);
728 }
729 }
730
731 #[cfg(all(feature = "num-bigint", feature = "num-traits"))]
732 #[test]
733 fn test_binops_no_copy_compiles() {
734 use num_bigint::BigUint;
735
736 let mut m = VanillaInt::<BigUint>::new(0u8.into(), &10u8.into());
737 let v: BigUint = 0u8.into();
738
739 _ = m.clone() + m.clone();
740 _ = m.clone() + &m;
741 _ = &m + m.clone();
742 _ = &m + &m;
743
744 _ = m.clone() + v.clone();
745 _ = m.clone() + &v;
746 _ = &m + v.clone();
747 _ = &m + &v;
748
749 m += m.clone();
750 m += &m.clone();
751 m += v.clone();
752 m += &v;
753
754 m -= m.clone();
755 m -= &m.clone();
756 m -= v.clone();
757 m -= &v;
758
759 m *= m.clone();
760 m *= &m.clone();
761 m *= v.clone();
762 m *= &v;
763
764 assert_eq!(m.residue(), 0u8.into());
765 }
766}