Fix checked shift RHS to u32, drop from PrimInt

Make the checked left and right shifts take a `u32` as right-hand side,
which is more consistent with the other checked operations. Also drop
`CheckedShl` and `CheckedShr` from the `PrimInt` trait, to not break
existing code. Add doctests for the two traits.
This commit is contained in:
Fabian Schuiki 2018-01-13 15:02:38 +01:00
parent 21dfae004c
commit 809ccff63f
2 changed files with 55 additions and 38 deletions

View File

@ -21,8 +21,6 @@ pub trait PrimInt
+ CheckedSub<Output=Self> + CheckedSub<Output=Self>
+ CheckedMul<Output=Self> + CheckedMul<Output=Self>
+ CheckedDiv<Output=Self> + CheckedDiv<Output=Self>
+ CheckedShl<usize, Output=Self>
+ CheckedShr<usize, Output=Self>
+ Saturating + Saturating
{ {
/// Returns the number of ones in the binary representation of `self`. /// Returns the number of ones in the binary representation of `self`.

View File

@ -91,53 +91,72 @@ checked_impl!(CheckedDiv, checked_div, i64);
checked_impl!(CheckedDiv, checked_div, isize); checked_impl!(CheckedDiv, checked_div, isize);
/// Performs a left shift that returns `None` on overflow. /// Performs a left shift that returns `None` on overflow.
pub trait CheckedShl<RHS>: Sized + Shl<RHS, Output=Self> { pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
/// Shifts a number to the left, checking for overflow. If overflow happens, `None` is /// Shifts a number to the left, checking for overflow. If overflow happens,
/// returned. /// `None` is returned.
fn checked_shl(&self, rhs: &RHS) -> Option<Self>; ///
/// ```
/// use num_traits::CheckedShl;
///
/// let x: u16 = 0x0001;
///
/// assert_eq!(CheckedShl::checked_shl(&x, 0), Some(0x0001));
/// assert_eq!(CheckedShl::checked_shl(&x, 1), Some(0x0002));
/// assert_eq!(CheckedShl::checked_shl(&x, 15), Some(0x8000));
/// assert_eq!(CheckedShl::checked_shl(&x, 16), None);
/// ```
fn checked_shl(&self, rhs: u32) -> Option<Self>;
} }
macro_rules! checked_shift_impl { macro_rules! checked_shift_impl {
($trait_name:ident, $method:ident, $rhs:ty, $t:ty) => { ($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name<$rhs> for $t { impl $trait_name for $t {
#[inline] #[inline]
fn $method(&self, rhs: &$rhs) -> Option<$t> { fn $method(&self, rhs: u32) -> Option<$t> {
// Note the cast to `u32` here: The standard library is somewhat inconsistent here. <$t>::$method(*self, rhs)
// The `Shl<T>` and `Shr<T>` trait are generic over the right-hand side `T`, but
// the checked versions of the shifts all operate on `u32`.
// TODO: Maybe we should use a conversion that can fail here. This would allow us
// to catch the case where `rhs` exceeds the `u32` accepted by the stdlib, and
// return a `None` instead.
<$t>::$method(*self, *rhs as u32)
} }
} }
} }
} }
macro_rules! checked_shift_impl_all { checked_shift_impl!(CheckedShl, checked_shl, u8);
($trait_name:ident, $method:ident, $($t:ty)*) => ($( checked_shift_impl!(CheckedShl, checked_shl, u16);
checked_shift_impl! { $trait_name, $method, u8 , $t } checked_shift_impl!(CheckedShl, checked_shl, u32);
checked_shift_impl! { $trait_name, $method, u16 , $t } checked_shift_impl!(CheckedShl, checked_shl, u64);
checked_shift_impl! { $trait_name, $method, u32 , $t } checked_shift_impl!(CheckedShl, checked_shl, usize);
checked_shift_impl! { $trait_name, $method, u64 , $t }
checked_shift_impl! { $trait_name, $method, usize, $t }
checked_shift_impl! { $trait_name, $method, i8 , $t } checked_shift_impl!(CheckedShl, checked_shl, i8);
checked_shift_impl! { $trait_name, $method, i16 , $t } checked_shift_impl!(CheckedShl, checked_shl, i16);
checked_shift_impl! { $trait_name, $method, i32 , $t } checked_shift_impl!(CheckedShl, checked_shl, i32);
checked_shift_impl! { $trait_name, $method, i64 , $t } checked_shift_impl!(CheckedShl, checked_shl, i64);
checked_shift_impl! { $trait_name, $method, isize, $t } checked_shift_impl!(CheckedShl, checked_shl, isize);
)*)
}
checked_shift_impl_all!(CheckedShl, checked_shl, u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
/// Performs a right shift that returns `None` on overflow. /// Performs a right shift that returns `None` on overflow.
pub trait CheckedShr<RHS>: Sized + Shr<RHS, Output=Self> { pub trait CheckedShr: Sized + Shr<u32, Output=Self> {
/// Shifts a number to the left, checking for overflow. If overflow happens, `None` is /// Shifts a number to the left, checking for overflow. If overflow happens,
/// returned. /// `None` is returned.
fn checked_shr(&self, rhs: &RHS) -> Option<Self>; ///
/// ```
/// use num_traits::CheckedShr;
///
/// let x: u16 = 0x8000;
///
/// assert_eq!(CheckedShr::checked_shr(&x, 0), Some(0x8000));
/// assert_eq!(CheckedShr::checked_shr(&x, 1), Some(0x4000));
/// assert_eq!(CheckedShr::checked_shr(&x, 15), Some(0x0001));
/// assert_eq!(CheckedShr::checked_shr(&x, 16), None);
/// ```
fn checked_shr(&self, rhs: u32) -> Option<Self>;
} }
checked_shift_impl_all!(CheckedShr, checked_shr, u8 u16 u32 u64 usize i8 i16 i32 i64 isize); checked_shift_impl!(CheckedShr, checked_shr, u8);
checked_shift_impl!(CheckedShr, checked_shr, u16);
checked_shift_impl!(CheckedShr, checked_shr, u32);
checked_shift_impl!(CheckedShr, checked_shr, u64);
checked_shift_impl!(CheckedShr, checked_shr, usize);
checked_shift_impl!(CheckedShr, checked_shr, i8);
checked_shift_impl!(CheckedShr, checked_shr, i16);
checked_shift_impl!(CheckedShr, checked_shr, i32);
checked_shift_impl!(CheckedShr, checked_shr, i64);
checked_shift_impl!(CheckedShr, checked_shr, isize);