use gen_ops::{gen_ops, gen_ops_ex};
use paste;
const EXPECTED_RES:[(i32, i32);10] = [
(7, 5), (3, 1), (10, 6), (2, 1), (1, 1), (0, 2), (7, 3), (7, 1), (20, 12), (1, 0) ];
macro_rules! generate_asgn_test {
((refs $lr:tt $rr:tt) $($ex:tt)?) => {
crate::paste::paste! {
mod [< $lr $rr $($ex _)? asgn >] {
use super::*;
#[derive(Clone, Copy, PartialEq, Debug)]
struct IntPair(pub i32, pub i32);
impl From<(i32, i32)> for IntPair {
#[inline]
fn from((a,b):(i32, i32))->IntPair {
IntPair(a,b)
}
}
generate_asgn_macro!($lr $rr $($ex)?);
#[test]
fn [< $lr $rr $($ex _)? asgn_test >]() {
#[allow(unused_mut)]
let mut b = 2;
gen_asserts!(b (refs $lr $rr));
}
}
}
};
}
macro_rules! generate_asgn_macro {
(@ex ($ltype:ty = $($l:tt)?) ($rtype:ty = $($r:tt)?) ex) => {
gen_ops_ex!(
types $($l)? $ltype , $($r)? $rtype;
for += call |a:&mut IntPair, b:&i32| {
a.0 += b;
a.1 += b;
};
for -= call |a:&mut IntPair, b:&i32| {
a.0 -= b;
a.1 -= b;
};
for /= call |a:&mut IntPair, b:&i32| {
a.0 /= b;
a.1 /= b;
};
for *= call |a:&mut IntPair, b:&i32| {
a.0 *= b;
a.1 *= b;
};
for %= call |a:&mut IntPair, b:&i32| {
a.0 %= b;
a.1 %= b;
};
for &= call |a:&mut IntPair, b:&i32| {
a.0 &= b;
a.1 &= b;
};
for |= call |a:&mut IntPair, b:&i32| {
a.0 |= b;
a.1 |= b;
};
for ^= call |a:&mut IntPair, b:&i32| {
a.0 ^= b;
a.1 ^= b;
};
for <<= call |a:&mut IntPair, b:&i32| {
a.0 <<= b;
a.1 <<= b;
};
for >>= call |a:&mut IntPair, b:&i32| {
a.0 >>= b;
a.1 >>= b;
};
);
};
(@ex ($ltype:ty) ($rtype:ty)) => {
gen_ops!(
types $ltype , $rtype;
for += call |a:&mut IntPair, b:&i32| {
a.0 += b;
a.1 += b;
};
for -= call |a:&mut IntPair, b:&i32| {
a.0 -= b;
a.1 -= b;
};
for /= call |a:&mut IntPair, b:&i32| {
a.0 /= b;
a.1 /= b;
};
for *= call |a:&mut IntPair, b:&i32| {
a.0 *= b;
a.1 *= b;
};
for %= call |a:&mut IntPair, b:&i32| {
a.0 %= b;
a.1 %= b;
};
for &= call |a:&mut IntPair, b:&i32| {
a.0 &= b;
a.1 &= b;
};
for |= call |a:&mut IntPair, b:&i32| {
a.0 |= b;
a.1 |= b;
};
for ^= call |a:&mut IntPair, b:&i32| {
a.0 ^= b;
a.1 ^= b;
};
for <<= call |a:&mut IntPair, b:&i32| {
a.0 <<= b;
a.1 <<= b;
};
for >>= call |a:&mut IntPair, b:&i32| {
a.0 >>= b;
a.1 >>= b;
};
);
};
(@ex_rhs ($l:ty) own_) => {
generate_asgn_macro!(@ex ($l) (i32));
};
(@ex_rhs ($l:ty) ref_) => {
generate_asgn_macro!(@ex ($l) (&i32));
};
(@ex_rhs ($l:ty) mut_) => {
generate_asgn_macro!(@ex ($l) (&mut i32));
};
(@ex_rhs ($lhs:ty =$($l:tt)?) own_ ex) => {
generate_asgn_macro!(@ex ($lhs =$($l)?) (i32 =) ex);
};
(@ex_rhs ($lhs:ty =$($l:tt)?) ref_ ex) => {
generate_asgn_macro!(@ex ($lhs =$($l)?) (&i32 =) ex);
};
(@ex_rhs ($lhs:ty =$($l:tt)?) mut_ ex) => {
generate_asgn_macro!(@ex ($lhs =$($l)?) (&mut i32 =) ex);
};
(@ex_rhs ($lhs:ty =$($l:tt)?) ref_own_ ex) => {
generate_asgn_macro!(@ex ($lhs =$($l)?) (i32 =ref) ex);
};
(@ex_rhs ($lhs:ty =$($l:tt)?) all_ ex) => {
generate_asgn_macro!(@ex ($lhs =$($l)?) (i32 = mut) ex);
};
(own_ $r:tt) => {
generate_asgn_macro!(@ex_rhs (IntPair) $r);
};
(mut_ $r:tt ) => {
generate_asgn_macro!(@ex_rhs (&mut IntPair) $r);
};
(own_ $r:tt ex) => {
generate_asgn_macro!(@ex_rhs (IntPair =) $r ex);
};
(mut_ $r:tt ex) => {
generate_asgn_macro!(@ex_rhs (&mut IntPair =) $r ex);
};
(all_ $r:tt ex) => {
generate_asgn_macro!(@ex_rhs (IntPair =mut) $r ex);
};
}
macro_rules! gen_asserts {
(@ops (refs ($ref:tt $res:ident) ($r:expr)) ($op1:tt $ind1:tt) $(($op:tt $ind:tt))+) => {
gen_asserts!(@ops2 (refs ($ref $res) ($r)) ($op1 $ind1));
gen_asserts!(@ops (refs ($ref $res) ($r)) $(($op $ind))+);
};
(@ops (refs ($ref:tt $res:ident) ($r:expr)) ($op1:tt $ind1:tt)) => {
gen_asserts!(@ops2 (refs ($ref $res) ($r)) ($op1 $ind1));
};
(@ops2 (refs (mut_ $res:ident) ($r:expr)) ($op1:tt $ind1:tt)) => {
{
let mut x = &mut $res [$ind1];
x $op1 $r;
}
};
(@ops2 (refs (own_ $res:ident) ($r:expr)) ($op1:tt $ind1:tt)) => {
$res[$ind1] $op1 $r;
};
(@asrt $l:tt ($r:expr)) => {
{
let mut actual_res = [IntPair(5, 3); 10];
gen_asserts!(@ops (refs ($l actual_res) ($r))
(+= 0) (-= 1) (*= 2) (/= 3) (%= 4)
(&= 5) (|= 6) (^= 7) (<<= 8) (>>= 9));
actual_res.iter().zip(EXPECTED_RES).for_each(|(res,exp)|{
assert_eq!(*res, Into::<IntPair>::into(exp), "\nresult={:?}", actual_res);
});
}
};
((refs own_ ($r:expr))) => {
gen_asserts!(@asrt own_ ($r));
};
((refs mut_ ($r:expr))) => {
gen_asserts!(@asrt mut_ ($r));
};
((refs all_ ($r:expr))) => {
gen_asserts!(@asrt own_ ($r));
gen_asserts!(@asrt mut_ ($r));
};
($b:ident (refs $l:tt own_)) => {
gen_asserts!((refs $l ($b)));
};
($b:ident (refs $l:tt ref_)) => {
gen_asserts!((refs $l (&$b)));
};
($b:ident (refs $l:tt mut_)) => {
gen_asserts!((refs $l (&mut $b)));
};
($b:ident (refs $l:tt ref_own_)) => {
gen_asserts!((refs $l ($b)));
gen_asserts!((refs $l (&$b)));
};
($b:ident (refs $l:tt all_)) => {
gen_asserts!((refs $l ($b)));
gen_asserts!((refs $l (&$b)));
gen_asserts!((refs $l (&mut $b)));
};
}
generate_asgn_test!((refs own_ own_));
generate_asgn_test!((refs own_ ref_));
generate_asgn_test!((refs own_ mut_));
generate_asgn_test!((refs mut_ own_));
generate_asgn_test!((refs mut_ ref_));
generate_asgn_test!((refs mut_ mut_));
generate_asgn_test!((refs own_ ref_own_) ex);
generate_asgn_test!((refs own_ all_) ex);
generate_asgn_test!((refs mut_ ref_own_) ex);
generate_asgn_test!((refs mut_ all_) ex);
generate_asgn_test!((refs all_ own_) ex);
generate_asgn_test!((refs all_ ref_) ex);
generate_asgn_test!((refs all_ mut_) ex);
generate_asgn_test!((refs all_ ref_own_) ex);
generate_asgn_test!((refs all_ all_) ex);