1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
macro_rules! forward_symmetric {
    (
        $(#[$cattr:meta])*
        impl $tn:ident($name:ident, $cname:ident, $wname:ident, $oname:ident) for $target:ty
    ) => {
        forward_symmetric!(
            $(#[$cattr])*
            impl $tn<$target>($name, $cname, $wname, $oname) for $target
        );
    };
    (
        $(#[$cattr:meta])*
        impl $tn:ident<$arg:ty>($name:ident, $cname:ident, $wname:ident, $oname:ident) for $target:ty
    ) => {
        forward_impl! {
            $(#[$cattr])*
            impl $tn<
                $arg;
                $arg { y => y };
                Wrapping<$arg> { x => x.0 }
            > ($name, $cname, $wname, $oname) for $target, "arithmetic operation overflowed"
        }
    }
}

macro_rules! forward_shift {
    (
        $(#[$cattr:meta])*
        impl $tn:ident($name:ident, $cname:ident, $wname:ident, $oname:ident) for $target:ty
    ) => {
        forward_impl! {
            $(#[$cattr])*
            impl $tn<
                u32;
                u8|u16|u32|u64|usize|i8|i16|i32|i64|isize { y => y.to_u32().unwrap_or_else(|| panic!("shift operation overflowed")) };
                u32 { x => x }
            > ($name, $cname, $wname, $oname) for $target, "shift operation overflowed"
        }
    }
}

macro_rules! forward_assign {
    ($tn:ident($name:ident, $fwd:ident) for $target:ty) => {
        forward_assign!($tn<$target>($name, $fwd) for $target);
    };
    ($tn:ident<$($targ:ty)|+>($name:ident, $fwd:ident) for $target:ty) => {
        $(impl $tn<$targ> for $target {
            fn $name(&mut self, other: $targ) {
                *self = self.$fwd(other);
            }
        })+
    }
}

macro_rules! forward_impl {
    (
        $(#[$cattr:meta])*
        impl $tn:ident<
            $arg:ty;
            $($targ:ty)|+ { $t:pat => $uncheck_cast:expr };
            $wrarg:ty { $u:pat => $unwrap:expr }
        > ($name:ident, $cname:ident, $wname:ident, $oname:ident) for $target:ty,
        $emsg:expr
    ) => {
        impl $target {
            $(#[$cattr])*
            pub fn $cname(self, other: $arg) -> Option<$target> {
                match self.$oname(other) {
                    (v, false) => Some(v),
                    (_, true) => None,
                }
            }
        }

        $(impl $tn<$targ> for $target {
            type Output = Self;
            #[cfg(debug_assertions)]
            #[allow(unused_comparisons, overflowing_literals)]
            fn $name(self, other: $targ) -> Self {
                let other = match other {
                    $t => $uncheck_cast,
                };
                self.$cname(other).unwrap_or_else(|| panic!($emsg))
            }
            #[cfg(not(debug_assertions))]
            fn $name(self, other: $targ) -> Self {
                self.$wname(match other { $t => $uncheck_cast })
            }
        })+

        impl $tn<$wrarg> for Wrapping<$target> {
            type Output = Self;
            fn $name(self, other: $wrarg) -> Self {
                match other {
                    $u => Wrapping((self.0).$wname($unwrap))
                }
            }
        }
    }
}