|
@@ -1,4 +1,4 @@
|
|
|
-use std::ops::{Add, Sub, Mul, Div};
|
|
|
+use std::ops::{Add, Sub, Mul, Div, Shl, Shr};
|
|
|
|
|
|
/// Performs addition that returns `None` instead of wrapping around on
|
|
|
/// overflow.
|
|
@@ -90,3 +90,54 @@ checked_impl!(CheckedDiv, checked_div, i32);
|
|
|
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>;
|
|
|
+}
|
|
|
+
|
|
|
+macro_rules! checked_shift_impl {
|
|
|
+ ($trait_name:ident, $method:ident, $rhs:ty, $t:ty) => {
|
|
|
+ impl $trait_name<$rhs> 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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+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! { $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);
|
|
|
+
|
|
|
+/// 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>;
|
|
|
+}
|
|
|
+
|
|
|
+checked_shift_impl_all!(CheckedShr, checked_shr, u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
|