macro_rules! mul_impls { ($name: ident, $dbl: ident) => { impl MulAssign<$name> for $name { fn mul_assign(&mut self, rhs: $name) { self.mul_assign(&rhs); } } impl<'a> MulAssign<&'a $name> for $name { fn mul_assign(&mut self, rhs: &$name) { self.value *= &rhs.value; self.negative = !self.value.is_zero() && (self.negative != rhs.negative); } } impl Mul<$name> for $name { type Output = $dbl; fn mul(self, rhs: $name) -> $dbl { &self * &rhs } } impl<'a> Mul<&'a $name> for $name { type Output = $dbl; fn mul(self, rhs: &$name) -> $dbl { &self * rhs } } impl<'a> Mul<$name> for &'a $name { type Output = $dbl; fn mul(self, rhs: $name) -> $dbl { self * &rhs } } impl<'a,'b> Mul<&'a $name> for &'b $name { type Output = $dbl; fn mul(self, rhs: &$name) -> $dbl { let outval = &self.value * &rhs.value; let zero = outval.is_zero(); $dbl { value: outval, negative: !zero && (self.negative != rhs.negative) } } } } } #[cfg(test)] macro_rules! generate_sigmul_tests { ($sname: ident, $name: ident, $lname: ident, $dbl: ident, $udbl: ident) => { #[test] fn $lname() { generate_sigmul_tests!(body $sname, $name, $dbl, $udbl); } }; (ignore $sname: ident, $name: ident, $lname: ident, $dbl: ident, $udbl: ident) => { #[test] #[ignore] fn $lname() { generate_sigmul_tests!(body $sname, $name, $dbl, $udbl); } }; (body $sname: ident, $name: ident, $dbl: ident, $udbl: ident) => { let fname = build_test_path("sigmul", stringify!($sname)); run_test(fname.to_string(), 3, |case| { let (nega, abytes) = case.get("a").unwrap(); let (negb, bbytes) = case.get("b").unwrap(); let (negc, cbytes) = case.get("c").unwrap(); let mut a = $sname::new(*nega, $name::from_bytes(abytes)); let b = $sname::new(*negb, $name::from_bytes(bbytes)); let c = $dbl::new(*negc, $udbl::from_bytes(cbytes)); assert_eq!(c, &a * &b, "base mul"); a *= b; assert_eq!($sname::from(c), a, "in-place mul"); }); }; }