diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index a7d5fcafd5603..72f0d77f68bac 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -12,13 +12,13 @@ #![unstable(feature = "wrapping", reason = "may be removed or relocated", issue = "27755")] -pub use intrinsics::{add_with_overflow, sub_with_overflow, mul_with_overflow}; +use intrinsics::{add_with_overflow, sub_with_overflow, mul_with_overflow}; use super::Wrapping; use ops::*; -use ::{i8,i16,i32,i64}; +use ::{i8, i16, i32, i64, isize}; pub trait OverflowingOps { fn overflowing_add(self, rhs: Self) -> (Self, bool); @@ -33,15 +33,71 @@ pub trait OverflowingOps { fn overflowing_shr(self, rhs: u32) -> (Self, bool); } -macro_rules! sh_impl { - ($t:ty, $f:ty) => ( +macro_rules! sh_impl_signed { + ($t:ident, $f:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] impl Shl<$f> for Wrapping<$t> { type Output = Wrapping<$t>; #[inline(always)] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0 << other) + if other < 0 { + Wrapping(self.0 >> (-other & self::shift_max::$t as $f)) + } else { + Wrapping(self.0 << (other & self::shift_max::$t as $f)) + } + } + } + + #[unstable(feature = "wrapping_impls", reason = "recently added", issue = "30524")] + impl ShlAssign<$f> for Wrapping<$t> { + #[inline(always)] + fn shl_assign(&mut self, other: $f) { + *self = *self << other; + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Shr<$f> for Wrapping<$t> { + type Output = Wrapping<$t>; + + #[inline(always)] + fn shr(self, other: $f) -> Wrapping<$t> { + if other < 0 { + Wrapping(self.0 << (-other & self::shift_max::$t as $f)) + } else { + Wrapping(self.0 >> (other & self::shift_max::$t as $f)) + } + } + } + + #[unstable(feature = "wrapping_impls", reason = "recently added", issue = "30524")] + impl ShrAssign<$f> for Wrapping<$t> { + #[inline(always)] + fn shr_assign(&mut self, other: $f) { + *self = *self >> other; + } + } + ) +} + +macro_rules! sh_impl_unsigned { + ($t:ident, $f:ident) => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl Shl<$f> for Wrapping<$t> { + type Output = Wrapping<$t>; + + #[inline(always)] + fn shl(self, other: $f) -> Wrapping<$t> { + Wrapping(self.0 << (other & self::shift_max::$t as $f)) + } + } + + #[unstable(feature = "wrapping_impls", reason = "recently added", issue = "30524")] + impl ShlAssign<$f> for Wrapping<$t> { + #[inline(always)] + fn shl_assign(&mut self, other: $f) { + *self = *self << other; } } @@ -51,7 +107,15 @@ macro_rules! sh_impl { #[inline(always)] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0 >> other) + Wrapping(self.0 >> (other & self::shift_max::$t as $f)) + } + } + + #[unstable(feature = "wrapping_impls", reason = "recently added", issue = "30524")] + impl ShrAssign<$f> for Wrapping<$t> { + #[inline(always)] + fn shr_assign(&mut self, other: $f) { + *self = *self >> other; } } ) @@ -59,23 +123,24 @@ macro_rules! sh_impl { // FIXME (#23545): uncomment the remaining impls macro_rules! sh_impl_all { - ($($t:ty)*) => ($( - // sh_impl! { $t, u8 } - // sh_impl! { $t, u16 } - // sh_impl! { $t, u32 } - // sh_impl! { $t, u64 } - sh_impl! { $t, usize } - - // sh_impl! { $t, i8 } - // sh_impl! { $t, i16 } - // sh_impl! { $t, i32 } - // sh_impl! { $t, i64 } - // sh_impl! { $t, isize } + ($($t:ident)*) => ($( + sh_impl_unsigned! { $t, u8 } + sh_impl_unsigned! { $t, u16 } + sh_impl_unsigned! { $t, u32 } + sh_impl_unsigned! { $t, u64 } + sh_impl_unsigned! { $t, usize } + + sh_impl_signed! { $t, i8 } + sh_impl_signed! { $t, i16 } + sh_impl_signed! { $t, i32 } + sh_impl_signed! { $t, i64 } + sh_impl_signed! { $t, isize } )*) } sh_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +// FIXME(30524): impl Op for Wrapping, impl OpAssign for Wrapping macro_rules! wrapping_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -88,6 +153,14 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl AddAssign for Wrapping<$t> { + #[inline(always)] + fn add_assign(&mut self, other: Wrapping<$t>) { + *self = *self + other; + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Sub for Wrapping<$t> { type Output = Wrapping<$t>; @@ -98,6 +171,14 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl SubAssign for Wrapping<$t> { + #[inline(always)] + fn sub_assign(&mut self, other: Wrapping<$t>) { + *self = *self - other; + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Mul for Wrapping<$t> { type Output = Wrapping<$t>; @@ -108,6 +189,14 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl MulAssign for Wrapping<$t> { + #[inline(always)] + fn mul_assign(&mut self, other: Wrapping<$t>) { + *self = *self * other; + } + } + #[stable(feature = "wrapping_div", since = "1.3.0")] impl Div for Wrapping<$t> { type Output = Wrapping<$t>; @@ -118,6 +207,32 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl DivAssign for Wrapping<$t> { + #[inline(always)] + fn div_assign(&mut self, other: Wrapping<$t>) { + *self = *self / other; + } + } + + #[unstable(feature = "wrapping_impls", reason = "recently added", issue = "30524")] + impl Rem for Wrapping<$t> { + type Output = Wrapping<$t>; + + #[inline(always)] + fn rem(self, other: Wrapping<$t>) -> Wrapping<$t> { + Wrapping(self.0.wrapping_rem(other.0)) + } + } + + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl RemAssign for Wrapping<$t> { + #[inline(always)] + fn rem_assign(&mut self, other: Wrapping<$t>) { + *self = *self % other; + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Not for Wrapping<$t> { type Output = Wrapping<$t>; @@ -138,6 +253,14 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitXorAssign for Wrapping<$t> { + #[inline(always)] + fn bitxor_assign(&mut self, other: Wrapping<$t>) { + *self = *self ^ other; + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl BitOr for Wrapping<$t> { type Output = Wrapping<$t>; @@ -148,6 +271,14 @@ macro_rules! wrapping_impl { } } + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitOrAssign for Wrapping<$t> { + #[inline(always)] + fn bitor_assign(&mut self, other: Wrapping<$t>) { + *self = *self | other; + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl BitAnd for Wrapping<$t> { type Output = Wrapping<$t>; @@ -157,6 +288,14 @@ macro_rules! wrapping_impl { Wrapping(self.0 & other.0) } } + + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitAndAssign for Wrapping<$t> { + #[inline(always)] + fn bitand_assign(&mut self, other: Wrapping<$t>) { + *self = *self & other; + } + } )*) } @@ -165,15 +304,29 @@ wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } mod shift_max { #![allow(non_upper_case_globals)] + #[cfg(target_pointer_width = "32")] + mod platform { + pub const usize: u32 = super::u32; + pub const isize: u32 = super::i32; + } + + #[cfg(target_pointer_width = "64")] + mod platform { + pub const usize: u32 = super::u64; + pub const isize: u32 = super::i64; + } + pub const i8: u32 = (1 << 3) - 1; pub const i16: u32 = (1 << 4) - 1; pub const i32: u32 = (1 << 5) - 1; pub const i64: u32 = (1 << 6) - 1; + pub use self::platform::isize; pub const u8: u32 = i8; pub const u16: u32 = i16; pub const u32: u32 = i32; pub const u64: u32 = i64; + pub use self::platform::usize; } macro_rules! signed_overflowing_impl { @@ -288,193 +441,5 @@ macro_rules! unsigned_overflowing_impl { )*) } -signed_overflowing_impl! { i8 i16 i32 i64 } -unsigned_overflowing_impl! { u8 u16 u32 u64 } - -#[cfg(target_pointer_width = "64")] -impl OverflowingOps for usize { - #[inline(always)] - fn overflowing_add(self, rhs: usize) -> (usize, bool) { - unsafe { - add_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_sub(self, rhs: usize) -> (usize, bool) { - unsafe { - sub_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_mul(self, rhs: usize) -> (usize, bool) { - unsafe { - mul_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_div(self, rhs: usize) -> (usize, bool) { - let (r, f) = (self as u64).overflowing_div(rhs as u64); - (r as usize, f) - } - #[inline(always)] - fn overflowing_rem(self, rhs: usize) -> (usize, bool) { - let (r, f) = (self as u64).overflowing_rem(rhs as u64); - (r as usize, f) - } - #[inline(always)] - fn overflowing_neg(self) -> (usize, bool) { - let (r, f) = (self as u64).overflowing_neg(); - (r as usize, f) - } - #[inline(always)] - fn overflowing_shl(self, rhs: u32) -> (usize, bool) { - let (r, f) = (self as u64).overflowing_shl(rhs); - (r as usize, f) - } - #[inline(always)] - fn overflowing_shr(self, rhs: u32) -> (usize, bool) { - let (r, f) = (self as u64).overflowing_shr(rhs); - (r as usize, f) - } -} - -#[cfg(target_pointer_width = "32")] -impl OverflowingOps for usize { - #[inline(always)] - fn overflowing_add(self, rhs: usize) -> (usize, bool) { - unsafe { - add_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_sub(self, rhs: usize) -> (usize, bool) { - unsafe { - sub_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_mul(self, rhs: usize) -> (usize, bool) { - unsafe { - mul_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_div(self, rhs: usize) -> (usize, bool) { - let (r, f) = (self as u32).overflowing_div(rhs as u32); - (r as usize, f) - } - #[inline(always)] - fn overflowing_rem(self, rhs: usize) -> (usize, bool) { - let (r, f) = (self as u32).overflowing_rem(rhs as u32); - (r as usize, f) - } - #[inline(always)] - fn overflowing_neg(self) -> (usize, bool) { - let (r, f) = (self as u32).overflowing_neg(); - (r as usize, f) - } - #[inline(always)] - fn overflowing_shl(self, rhs: u32) -> (usize, bool) { - let (r, f) = (self as u32).overflowing_shl(rhs); - (r as usize, f) - } - #[inline(always)] - fn overflowing_shr(self, rhs: u32) -> (usize, bool) { - let (r, f) = (self as u32).overflowing_shr(rhs); - (r as usize, f) - } -} - -#[cfg(target_pointer_width = "64")] -impl OverflowingOps for isize { - #[inline(always)] - fn overflowing_add(self, rhs: isize) -> (isize, bool) { - unsafe { - add_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_sub(self, rhs: isize) -> (isize, bool) { - unsafe { - sub_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_mul(self, rhs: isize) -> (isize, bool) { - unsafe { - mul_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_div(self, rhs: isize) -> (isize, bool) { - let (r, f) = (self as i64).overflowing_div(rhs as i64); - (r as isize, f) - } - #[inline(always)] - fn overflowing_rem(self, rhs: isize) -> (isize, bool) { - let (r, f) = (self as i64).overflowing_rem(rhs as i64); - (r as isize, f) - } - #[inline(always)] - fn overflowing_neg(self) -> (isize, bool) { - let (r, f) = (self as i64).overflowing_neg(); - (r as isize, f) - } - #[inline(always)] - fn overflowing_shl(self, rhs: u32) -> (isize, bool) { - let (r, f) = (self as i64).overflowing_shl(rhs); - (r as isize, f) - } - #[inline(always)] - fn overflowing_shr(self, rhs: u32) -> (isize, bool) { - let (r, f) = (self as i64).overflowing_shr(rhs); - (r as isize, f) - } -} - -#[cfg(target_pointer_width = "32")] -impl OverflowingOps for isize { - #[inline(always)] - fn overflowing_add(self, rhs: isize) -> (isize, bool) { - unsafe { - add_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_sub(self, rhs: isize) -> (isize, bool) { - unsafe { - sub_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_mul(self, rhs: isize) -> (isize, bool) { - unsafe { - mul_with_overflow(self, rhs) - } - } - #[inline(always)] - fn overflowing_div(self, rhs: isize) -> (isize, bool) { - let (r, f) = (self as i32).overflowing_div(rhs as i32); - (r as isize, f) - } - #[inline(always)] - fn overflowing_rem(self, rhs: isize) -> (isize, bool) { - let (r, f) = (self as i32).overflowing_rem(rhs as i32); - (r as isize, f) - } - #[inline(always)] - fn overflowing_neg(self) -> (isize, bool) { - let (r, f) = (self as i32).overflowing_neg(); - (r as isize, f) - } - #[inline(always)] - fn overflowing_shl(self, rhs: u32) -> (isize, bool) { - let (r, f) = (self as i32).overflowing_shl(rhs); - (r as isize, f) - } - #[inline(always)] - fn overflowing_shr(self, rhs: u32) -> (isize, bool) { - let (r, f) = (self as i32).overflowing_shr(rhs); - (r as isize, f) - } -} +signed_overflowing_impl! { i8 i16 i32 i64 isize } +unsigned_overflowing_impl! { u8 u16 u32 u64 usize } diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 28eff87bde3b7..545fd22cc5929 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -170,7 +170,7 @@ impl IsaacRng { const MIDPOINT: usize = RAND_SIZE_USIZE / 2; macro_rules! ind { - ($x:expr) => (self.mem[($x >> 2).0 as usize & (RAND_SIZE_USIZE - 1)] ) + ($x:expr) => (self.mem[($x >> 2u32).0 as usize & (RAND_SIZE_USIZE - 1)] ) } let r = [(0, MIDPOINT), (MIDPOINT, 0)]; @@ -452,7 +452,7 @@ impl Isaac64Rng { const MP_VEC: [(usize, usize); 2] = [(0, MIDPOINT), (MIDPOINT, 0)]; macro_rules! ind { ($x:expr) => { - *self.mem.get_unchecked((($x >> 3).0 as usize) & (RAND_SIZE_64 - 1)) + *self.mem.get_unchecked((($x >> 3u32).0 as usize) & (RAND_SIZE_64 - 1)) } } @@ -495,10 +495,10 @@ impl Isaac64Rng { }} } - rngstepp!(0, 21); - rngstepn!(1, 5); - rngstepp!(2, 12); - rngstepn!(3, 33); + rngstepp!(0, 21u32); + rngstepn!(1, 5u32); + rngstepp!(2, 12u32); + rngstepn!(3, 33u32); } } diff --git a/src/test/run-pass/num-wrapping.rs b/src/test/run-pass/num-wrapping.rs new file mode 100644 index 0000000000000..228f4cdd1aa37 --- /dev/null +++ b/src/test/run-pass/num-wrapping.rs @@ -0,0 +1,412 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// compile-flags: -C debug-assertions +// +// Test std::num::Wrapping for {uN, iN, usize, isize} + +#![feature(op_assign_traits, num_bits_bytes, test)] + +extern crate test; + +use std::num::Wrapping; +use std::ops::{ + Add, Sub, Mul, Div, Rem, BitXor, BitOr, BitAnd, + AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, BitXorAssign, BitOrAssign, BitAndAssign, + Shl, Shr, ShlAssign, ShrAssign +}; +use std::{i8, i16, i32, i64, isize, u8, u16, u32, u64, usize}; +use test::black_box; + +fn main() { + test_ops(); + test_op_assigns(); + test_sh_ops(); + test_sh_op_assigns(); +} + +fn test_ops() { + macro_rules! op_test { + ($op:ident ($lhs:expr, $rhs:expr) == $ans:expr) => { + assert_eq!(black_box(Wrapping($lhs).$op(Wrapping($rhs))), Wrapping($ans)); + // FIXME(30524): uncomment this test when it's implemented + // assert_eq!(black_box(Wrapping($lhs).$op($rhs)), Wrapping($ans)); + } + } + + op_test!(add(i8::MAX, 1) == i8::MIN); + op_test!(add(i16::MAX, 1) == i16::MIN); + op_test!(add(i32::MAX, 1) == i32::MIN); + op_test!(add(i64::MAX, 1) == i64::MIN); + op_test!(add(isize::MAX, 1) == isize::MIN); + + op_test!(add(u8::MAX, 1) == 0); + op_test!(add(u16::MAX, 1) == 0); + op_test!(add(u32::MAX, 1) == 0); + op_test!(add(u64::MAX, 1) == 0); + op_test!(add(usize::MAX, 1) == 0); + + + op_test!(sub(i8::MIN, 1) == i8::MAX); + op_test!(sub(i16::MIN, 1) == i16::MAX); + op_test!(sub(i32::MIN, 1) == i32::MAX); + op_test!(sub(i64::MIN, 1) == i64::MAX); + op_test!(sub(isize::MIN, 1) == isize::MAX); + + op_test!(sub(0u8, 1) == u8::MAX); + op_test!(sub(0u16, 1) == u16::MAX); + op_test!(sub(0u32, 1) == u32::MAX); + op_test!(sub(0u64, 1) == u64::MAX); + op_test!(sub(0usize, 1) == usize::MAX); + + + op_test!(mul(i8::MAX, 2) == -2); + op_test!(mul(i16::MAX, 2) == -2); + op_test!(mul(i32::MAX, 2) == -2); + op_test!(mul(i64::MAX, 2) == -2); + op_test!(mul(isize::MAX, 2) == -2); + + op_test!(mul(u8::MAX, 2) == u8::MAX - 1); + op_test!(mul(u16::MAX, 2) == u16::MAX - 1); + op_test!(mul(u32::MAX, 2) == u32::MAX - 1); + op_test!(mul(u64::MAX, 2) == u64::MAX - 1); + op_test!(mul(usize::MAX, 2) == usize::MAX - 1); + + + op_test!(div(i8::MIN, -1) == i8::MIN); + op_test!(div(i16::MIN, -1) == i16::MIN); + op_test!(div(i32::MIN, -1) == i32::MIN); + op_test!(div(i64::MIN, -1) == i64::MIN); + op_test!(div(isize::MIN, -1) == isize::MIN); + + + op_test!(rem(i8::MIN, -1) == 0); + op_test!(rem(i16::MIN, -1) == 0); + op_test!(rem(i32::MIN, -1) == 0); + op_test!(rem(i64::MIN, -1) == 0); + op_test!(rem(isize::MIN, -1) == 0); + + // these are not that interesting, just testing to make sure they are implemented correctly + op_test!(bitxor(0b101010i8, 0b100110) == 0b001100); + op_test!(bitxor(0b101010i16, 0b100110) == 0b001100); + op_test!(bitxor(0b101010i32, 0b100110) == 0b001100); + op_test!(bitxor(0b101010i64, 0b100110) == 0b001100); + op_test!(bitxor(0b101010isize, 0b100110) == 0b001100); + + op_test!(bitxor(0b101010u8, 0b100110) == 0b001100); + op_test!(bitxor(0b101010u16, 0b100110) == 0b001100); + op_test!(bitxor(0b101010u32, 0b100110) == 0b001100); + op_test!(bitxor(0b101010u64, 0b100110) == 0b001100); + op_test!(bitxor(0b101010usize, 0b100110) == 0b001100); + + + op_test!(bitor(0b101010i8, 0b100110) == 0b101110); + op_test!(bitor(0b101010i16, 0b100110) == 0b101110); + op_test!(bitor(0b101010i32, 0b100110) == 0b101110); + op_test!(bitor(0b101010i64, 0b100110) == 0b101110); + op_test!(bitor(0b101010isize, 0b100110) == 0b101110); + + op_test!(bitor(0b101010u8, 0b100110) == 0b101110); + op_test!(bitor(0b101010u16, 0b100110) == 0b101110); + op_test!(bitor(0b101010u32, 0b100110) == 0b101110); + op_test!(bitor(0b101010u64, 0b100110) == 0b101110); + op_test!(bitor(0b101010usize, 0b100110) == 0b101110); + + + op_test!(bitand(0b101010i8, 0b100110) == 0b100010); + op_test!(bitand(0b101010i16, 0b100110) == 0b100010); + op_test!(bitand(0b101010i32, 0b100110) == 0b100010); + op_test!(bitand(0b101010i64, 0b100110) == 0b100010); + op_test!(bitand(0b101010isize, 0b100110) == 0b100010); + + op_test!(bitand(0b101010u8, 0b100110) == 0b100010); + op_test!(bitand(0b101010u16, 0b100110) == 0b100010); + op_test!(bitand(0b101010u32, 0b100110) == 0b100010); + op_test!(bitand(0b101010u64, 0b100110) == 0b100010); + op_test!(bitand(0b101010usize, 0b100110) == 0b100010); +} + +fn test_op_assigns() { + macro_rules! op_assign_test { + ($op:ident ($initial:expr, $rhs:expr) == $ans:expr) => { + { + let mut tmp = Wrapping($initial); + tmp = black_box(tmp); + tmp.$op(Wrapping($rhs)); + assert_eq!(black_box(tmp), Wrapping($ans)); + } + // FIXME(30524): Uncomment this test + /* + { + let mut tmp = Wrapping($initial); + tmp = black_box(tmp); + tmp.$op($rhs); + assert_eq!(black_box(tmp), Wrapping($ans)); + } + */ + } + } + op_assign_test!(add_assign(i8::MAX, 1) == i8::MIN); + op_assign_test!(add_assign(i16::MAX, 1) == i16::MIN); + op_assign_test!(add_assign(i32::MAX, 1) == i32::MIN); + op_assign_test!(add_assign(i64::MAX, 1) == i64::MIN); + op_assign_test!(add_assign(isize::MAX, 1) == isize::MIN); + + op_assign_test!(add_assign(u8::MAX, 1) == u8::MIN); + op_assign_test!(add_assign(u16::MAX, 1) == u16::MIN); + op_assign_test!(add_assign(u32::MAX, 1) == u32::MIN); + op_assign_test!(add_assign(u64::MAX, 1) == u64::MIN); + op_assign_test!(add_assign(usize::MAX, 1) == usize::MIN); + + + op_assign_test!(sub_assign(i8::MIN, 1) == i8::MAX); + op_assign_test!(sub_assign(i16::MIN, 1) == i16::MAX); + op_assign_test!(sub_assign(i32::MIN, 1) == i32::MAX); + op_assign_test!(sub_assign(i64::MIN, 1) == i64::MAX); + op_assign_test!(sub_assign(isize::MIN, 1) == isize::MAX); + + op_assign_test!(sub_assign(u8::MIN, 1) == u8::MAX); + op_assign_test!(sub_assign(u16::MIN, 1) == u16::MAX); + op_assign_test!(sub_assign(u32::MIN, 1) == u32::MAX); + op_assign_test!(sub_assign(u64::MIN, 1) == u64::MAX); + op_assign_test!(sub_assign(usize::MIN, 1) == usize::MAX); + + + op_assign_test!(mul_assign(i8::MAX, 2) == -2); + op_assign_test!(mul_assign(i16::MAX, 2) == -2); + op_assign_test!(mul_assign(i32::MAX, 2) == -2); + op_assign_test!(mul_assign(i64::MAX, 2) == -2); + op_assign_test!(mul_assign(isize::MAX, 2) == -2); + + op_assign_test!(mul_assign(u8::MAX, 2) == u8::MAX - 1); + op_assign_test!(mul_assign(u16::MAX, 2) == u16::MAX - 1); + op_assign_test!(mul_assign(u32::MAX, 2) == u32::MAX - 1); + op_assign_test!(mul_assign(u64::MAX, 2) == u64::MAX - 1); + op_assign_test!(mul_assign(usize::MAX, 2) == usize::MAX - 1); + + + op_assign_test!(div_assign(i8::MIN, -1) == i8::MIN); + op_assign_test!(div_assign(i16::MIN, -1) == i16::MIN); + op_assign_test!(div_assign(i32::MIN, -1) == i32::MIN); + op_assign_test!(div_assign(i64::MIN, -1) == i64::MIN); + op_assign_test!(div_assign(isize::MIN, -1) == isize::MIN); + + + op_assign_test!(rem_assign(i8::MIN, -1) == 0); + op_assign_test!(rem_assign(i16::MIN, -1) == 0); + op_assign_test!(rem_assign(i32::MIN, -1) == 0); + op_assign_test!(rem_assign(i64::MIN, -1) == 0); + op_assign_test!(rem_assign(isize::MIN, -1) == 0); + + + // these are not that interesting, just testing to make sure they are implemented correctly + op_assign_test!(bitxor_assign(0b101010i8, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010i16, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010i32, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010i64, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010isize, 0b100110) == 0b001100); + + op_assign_test!(bitxor_assign(0b101010u8, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010u16, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010u32, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010u64, 0b100110) == 0b001100); + op_assign_test!(bitxor_assign(0b101010usize, 0b100110) == 0b001100); + + + op_assign_test!(bitor_assign(0b101010i8, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010i16, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010i32, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010i64, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010isize, 0b100110) == 0b101110); + + op_assign_test!(bitor_assign(0b101010u8, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010u16, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010u32, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010u64, 0b100110) == 0b101110); + op_assign_test!(bitor_assign(0b101010usize, 0b100110) == 0b101110); + + + op_assign_test!(bitand_assign(0b101010i8, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010i16, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010i32, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010i64, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010isize, 0b100110) == 0b100010); + + op_assign_test!(bitand_assign(0b101010u8, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010u16, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010u32, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010u64, 0b100110) == 0b100010); + op_assign_test!(bitand_assign(0b101010usize, 0b100110) == 0b100010); +} + +fn test_sh_ops() { + macro_rules! sh_test { + ($op:ident ($lhs:expr, $rhs:expr) == $ans:expr) => { + assert_eq!(black_box(Wrapping($lhs).$op($rhs)), Wrapping($ans)); + } + } + // NOTE: This will break for i8 if we ever get i/u128 + macro_rules! sh_test_all { + ($t:ty) => { + sh_test!(shl(i8::MAX, (i8::BITS + 1) as $t) == -2); + sh_test!(shl(i16::MAX, (i16::BITS + 1) as $t) == -2); + sh_test!(shl(i32::MAX, (i32::BITS + 1) as $t) == -2); + sh_test!(shl(i64::MAX, (i64::BITS + 1) as $t) == -2); + sh_test!(shl(isize::MAX, (isize::BITS + 1) as $t) == -2); + + sh_test!(shl(u8::MAX, (u8::BITS + 1) as $t) == u8::MAX - 1); + sh_test!(shl(u16::MAX, (u16::BITS + 1) as $t) == u16::MAX - 1); + sh_test!(shl(u32::MAX, (u32::BITS + 1) as $t) == u32::MAX - 1); + sh_test!(shl(u64::MAX, (u64::BITS + 1) as $t) == u64::MAX - 1); + sh_test!(shl(usize::MAX, (usize::BITS + 1) as $t) == usize::MAX - 1); + + + sh_test!(shr(i8::MAX, (i8::BITS + 1) as $t) == i8::MAX / 2); + sh_test!(shr(i16::MAX, (i16::BITS + 1) as $t) == i16::MAX / 2); + sh_test!(shr(i32::MAX, (i32::BITS + 1) as $t) == i32::MAX / 2); + sh_test!(shr(i64::MAX, (i64::BITS + 1) as $t) == i64::MAX / 2); + sh_test!(shr(isize::MAX, (isize::BITS + 1) as $t) == isize::MAX / 2); + + sh_test!(shr(u8::MAX, (u8::BITS + 1) as $t) == u8::MAX / 2); + sh_test!(shr(u16::MAX, (u16::BITS + 1) as $t) == u16::MAX / 2); + sh_test!(shr(u32::MAX, (u32::BITS + 1) as $t) == u32::MAX / 2); + sh_test!(shr(u64::MAX, (u64::BITS + 1) as $t) == u64::MAX / 2); + sh_test!(shr(usize::MAX, (usize::BITS + 1) as $t) == usize::MAX / 2); + } + } + macro_rules! sh_test_negative_all { + ($t:ty) => { + sh_test!(shr(i8::MAX, -((i8::BITS + 1) as $t)) == -2); + sh_test!(shr(i16::MAX, -((i16::BITS + 1) as $t)) == -2); + sh_test!(shr(i32::MAX, -((i32::BITS + 1) as $t)) == -2); + sh_test!(shr(i64::MAX, -((i64::BITS + 1) as $t)) == -2); + sh_test!(shr(isize::MAX, -((isize::BITS + 1) as $t)) == -2); + + sh_test!(shr(u8::MAX, -((u8::BITS + 1) as $t)) == u8::MAX - 1); + sh_test!(shr(u16::MAX, -((u16::BITS + 1) as $t)) == u16::MAX - 1); + sh_test!(shr(u32::MAX, -((u32::BITS + 1) as $t)) == u32::MAX - 1); + sh_test!(shr(u64::MAX, -((u64::BITS + 1) as $t)) == u64::MAX - 1); + sh_test!(shr(usize::MAX, -((usize::BITS + 1) as $t)) == usize::MAX - 1); + + + sh_test!(shl(i8::MAX, -((i8::BITS + 1) as $t)) == i8::MAX / 2); + sh_test!(shl(i16::MAX, -((i16::BITS + 1) as $t)) == i16::MAX / 2); + sh_test!(shl(i32::MAX, -((i32::BITS + 1) as $t)) == i32::MAX / 2); + sh_test!(shl(i64::MAX, -((i64::BITS + 1) as $t)) == i64::MAX / 2); + sh_test!(shl(isize::MAX, -((isize::BITS + 1) as $t)) == isize::MAX / 2); + + sh_test!(shl(u8::MAX, -((u8::BITS + 1) as $t)) == u8::MAX / 2); + sh_test!(shl(u16::MAX, -((u16::BITS + 1) as $t)) == u16::MAX / 2); + sh_test!(shl(u32::MAX, -((u32::BITS + 1) as $t)) == u32::MAX / 2); + sh_test!(shl(u64::MAX, -((u64::BITS + 1) as $t)) == u64::MAX / 2); + sh_test!(shl(usize::MAX, -((usize::BITS + 1) as $t)) == usize::MAX / 2); + } + } + sh_test_all!(i8); + sh_test_all!(u8); + sh_test_all!(i16); + sh_test_all!(u16); + sh_test_all!(i32); + sh_test_all!(u32); + sh_test_all!(i64); + sh_test_all!(u64); + sh_test_all!(isize); + sh_test_all!(usize); + + sh_test_negative_all!(i8); + sh_test_negative_all!(i16); + sh_test_negative_all!(i32); + sh_test_negative_all!(i64); + sh_test_negative_all!(isize); +} + +fn test_sh_op_assigns() { + macro_rules! sh_assign_test { + ($op:ident ($initial:expr, $rhs:expr) == $ans:expr) => {{ + let mut tmp = Wrapping($initial); + tmp = black_box(tmp); + tmp.$op($rhs); + assert_eq!(black_box(tmp), Wrapping($ans)); + }} + } + macro_rules! sh_assign_test_all { + ($t:ty) => { + sh_assign_test!(shl_assign(i8::MAX, (i8::BITS + 1) as $t) == -2); + sh_assign_test!(shl_assign(i16::MAX, (i16::BITS + 1) as $t) == -2); + sh_assign_test!(shl_assign(i32::MAX, (i32::BITS + 1) as $t) == -2); + sh_assign_test!(shl_assign(i64::MAX, (i64::BITS + 1) as $t) == -2); + sh_assign_test!(shl_assign(isize::MAX, (isize::BITS + 1) as $t) == -2); + + sh_assign_test!(shl_assign(u8::MAX, (u8::BITS + 1) as $t) == u8::MAX - 1); + sh_assign_test!(shl_assign(u16::MAX, (u16::BITS + 1) as $t) == u16::MAX - 1); + sh_assign_test!(shl_assign(u32::MAX, (u32::BITS + 1) as $t) == u32::MAX - 1); + sh_assign_test!(shl_assign(u64::MAX, (u64::BITS + 1) as $t) == u64::MAX - 1); + sh_assign_test!(shl_assign(usize::MAX, (usize::BITS + 1) as $t) == usize::MAX - 1); + + + sh_assign_test!(shr_assign(i8::MAX, (i8::BITS + 1) as $t) == i8::MAX / 2); + sh_assign_test!(shr_assign(i16::MAX, (i16::BITS + 1) as $t) == i16::MAX / 2); + sh_assign_test!(shr_assign(i32::MAX, (i32::BITS + 1) as $t) == i32::MAX / 2); + sh_assign_test!(shr_assign(i64::MAX, (i64::BITS + 1) as $t) == i64::MAX / 2); + sh_assign_test!(shr_assign(isize::MAX, (isize::BITS + 1) as $t) == isize::MAX / 2); + + sh_assign_test!(shr_assign(u8::MAX, (u8::BITS + 1) as $t) == u8::MAX / 2); + sh_assign_test!(shr_assign(u16::MAX, (u16::BITS + 1) as $t) == u16::MAX / 2); + sh_assign_test!(shr_assign(u32::MAX, (u32::BITS + 1) as $t) == u32::MAX / 2); + sh_assign_test!(shr_assign(u64::MAX, (u64::BITS + 1) as $t) == u64::MAX / 2); + sh_assign_test!(shr_assign(usize::MAX, (usize::BITS + 1) as $t) == usize::MAX / 2); + } + } + macro_rules! sh_assign_test_negative_all { + ($t:ty) => { + sh_assign_test!(shr_assign(i8::MAX, -((i8::BITS + 1) as $t)) == -2); + sh_assign_test!(shr_assign(i16::MAX, -((i16::BITS + 1) as $t)) == -2); + sh_assign_test!(shr_assign(i32::MAX, -((i32::BITS + 1) as $t)) == -2); + sh_assign_test!(shr_assign(i64::MAX, -((i64::BITS + 1) as $t)) == -2); + sh_assign_test!(shr_assign(isize::MAX, -((isize::BITS + 1) as $t)) == -2); + + sh_assign_test!(shr_assign(u8::MAX, -((u8::BITS + 1) as $t)) == u8::MAX - 1); + sh_assign_test!(shr_assign(u16::MAX, -((u16::BITS + 1) as $t)) == u16::MAX - 1); + sh_assign_test!(shr_assign(u32::MAX, -((u32::BITS + 1) as $t)) == u32::MAX - 1); + sh_assign_test!(shr_assign(u64::MAX, -((u64::BITS + 1) as $t)) == u64::MAX - 1); + sh_assign_test!(shr_assign(usize::MAX, -((usize::BITS + 1) as $t)) == usize::MAX - 1); + + + sh_assign_test!(shl_assign(i8::MAX, -((i8::BITS + 1) as $t)) == i8::MAX / 2); + sh_assign_test!(shl_assign(i16::MAX, -((i16::BITS + 1) as $t)) == i16::MAX / 2); + sh_assign_test!(shl_assign(i32::MAX, -((i32::BITS + 1) as $t)) == i32::MAX / 2); + sh_assign_test!(shl_assign(i64::MAX, -((i64::BITS + 1) as $t)) == i64::MAX / 2); + sh_assign_test!(shl_assign(isize::MAX, -((isize::BITS + 1) as $t)) == isize::MAX / 2); + + sh_assign_test!(shl_assign(u8::MAX, -((u8::BITS + 1) as $t)) == u8::MAX / 2); + sh_assign_test!(shl_assign(u16::MAX, -((u16::BITS + 1) as $t)) == u16::MAX / 2); + sh_assign_test!(shl_assign(u32::MAX, -((u32::BITS + 1) as $t)) == u32::MAX / 2); + sh_assign_test!(shl_assign(u64::MAX, -((u64::BITS + 1) as $t)) == u64::MAX / 2); + sh_assign_test!(shl_assign(usize::MAX, -((usize::BITS + 1) as $t)) == usize::MAX / 2); + } + } + + sh_assign_test_all!(i8); + sh_assign_test_all!(u8); + sh_assign_test_all!(i16); + sh_assign_test_all!(u16); + sh_assign_test_all!(i32); + sh_assign_test_all!(u32); + sh_assign_test_all!(i64); + sh_assign_test_all!(u64); + sh_assign_test_all!(isize); + sh_assign_test_all!(usize); + + sh_assign_test_negative_all!(i8); + sh_assign_test_negative_all!(i16); + sh_assign_test_negative_all!(i32); + sh_assign_test_negative_all!(i64); + sh_assign_test_negative_all!(isize); +}