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:
parent
21dfae004c
commit
809ccff63f
|
@ -21,8 +21,6 @@ pub trait PrimInt
|
|||
+ CheckedSub<Output=Self>
|
||||
+ CheckedMul<Output=Self>
|
||||
+ CheckedDiv<Output=Self>
|
||||
+ CheckedShl<usize, Output=Self>
|
||||
+ CheckedShr<usize, Output=Self>
|
||||
+ Saturating
|
||||
{
|
||||
/// Returns the number of ones in the binary representation of `self`.
|
||||
|
|
|
@ -91,53 +91,72 @@ checked_impl!(CheckedDiv, checked_div, i64);
|
|||
checked_impl!(CheckedDiv, checked_div, isize);
|
||||
|
||||
/// Performs a left shift that returns `None` on overflow.
|
||||
pub trait CheckedShl<RHS>: Sized + Shl<RHS, Output=Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens, `None` is
|
||||
/// returned.
|
||||
fn checked_shl(&self, rhs: &RHS) -> Option<Self>;
|
||||
pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
///
|
||||
/// ```
|
||||
/// 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 {
|
||||
($trait_name:ident, $method:ident, $rhs:ty, $t:ty) => {
|
||||
impl $trait_name<$rhs> for $t {
|
||||
($trait_name:ident, $method:ident, $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn $method(&self, rhs: &$rhs) -> Option<$t> {
|
||||
// Note the cast to `u32` here: The standard library is somewhat inconsistent here.
|
||||
// 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)
|
||||
fn $method(&self, rhs: u32) -> Option<$t> {
|
||||
<$t>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! checked_shift_impl_all {
|
||||
($trait_name:ident, $method:ident, $($t:ty)*) => ($(
|
||||
checked_shift_impl! { $trait_name, $method, u8 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, u16 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, u32 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, u64 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, usize, $t }
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u8);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u16);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u32);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, u64);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, usize);
|
||||
|
||||
checked_shift_impl! { $trait_name, $method, i8 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, i16 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, i32 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, i64 , $t }
|
||||
checked_shift_impl! { $trait_name, $method, isize, $t }
|
||||
)*)
|
||||
}
|
||||
|
||||
checked_shift_impl_all!(CheckedShl, checked_shl, u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i8);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i16);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i32);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i64);
|
||||
checked_shift_impl!(CheckedShl, checked_shl, isize);
|
||||
|
||||
/// Performs a right shift that returns `None` on overflow.
|
||||
pub trait CheckedShr<RHS>: Sized + Shr<RHS, Output=Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens, `None` is
|
||||
/// returned.
|
||||
fn checked_shr(&self, rhs: &RHS) -> Option<Self>;
|
||||
pub trait CheckedShr: Sized + Shr<u32, Output=Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
///
|
||||
/// ```
|
||||
/// 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);
|
||||
|
|
Loading…
Reference in New Issue