Impl Option*{Div,Mul,Rem}

Use the inner type for Rhs, as implemented for Duration.
These operations make sense without providing a "unit".
This commit is contained in:
François Laignel 2021-10-07 14:15:35 +02:00
parent f83b385487
commit 4bbd201377
2 changed files with 123 additions and 11 deletions

View file

@ -426,8 +426,6 @@ mod tests {
#[test]
fn checked_ops() {
use opt_ops::CheckedError;
assert_eq!(CT_1.checked_add(CT_1), Some(CT_2));
assert_eq!(CT_1.opt_checked_add(CT_1), Ok(Some(CT_2)));
@ -439,7 +437,7 @@ mod tests {
assert!(ClockTime::MAX.checked_add(CT_1).is_none());
assert_eq!(
ClockTime::MAX.opt_checked_add(Some(CT_1)),
Err(CheckedError::Overflow)
Err(opt_ops::Error::Overflow)
);
assert_eq!(CT_2.checked_sub(CT_1), Some(CT_1));
@ -454,7 +452,7 @@ mod tests {
assert!(CT_1.checked_sub(CT_2).is_none());
assert_eq!(
Some(CT_1).opt_checked_sub(CT_2),
Err(CheckedError::Overflow)
Err(opt_ops::Error::Overflow)
);
}

View file

@ -111,14 +111,69 @@ macro_rules! impl_common_ops_for_newtype_uint(
}
}
// FIXME add overflowing_add
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub fn wrapping_add(self, rhs: Self) -> Self {
self.overflowing_add(rhs).0
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: $inner_type) -> Option<Self> {
match self.0.checked_div(rhs) {
Some(val) => Some(Self(val)),
None => None,
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub const fn checked_mul(self, rhs: $inner_type) -> Option<Self> {
match self.0.checked_mul(rhs) {
Some(res) if res <= Self::MAX.0 => Some(Self(res)),
_ => None,
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub const fn saturating_mul(self, rhs: $inner_type) -> Self {
let res = self.0.saturating_mul(rhs);
if res < Self::MAX.0 {
Self(res)
} else {
Self::MAX
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub fn overflowing_mul(self, rhs: $inner_type) -> (Self, bool) {
let self_u128 = self.0 as u128;
let rhs_128 = rhs as u128;
let res_u128 = self_u128 * rhs_128;
if res_u128 <= Self::MAX.0 as u128 {
(Self(<$inner_type>::try_from(res_u128).unwrap()), false)
} else {
(Self(<$inner_type>::try_from((res_u128 - Self::MAX.0 as u128 - 1) as u64).unwrap()), true)
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub fn wrapping_mul(self, rhs: $inner_type) -> Self {
self.overflowing_mul(rhs).0
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: $inner_type) -> Option<Self> {
match self.0.checked_rem(rhs) {
Some(val) => Some(Self(val)),
None => None,
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
// FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2
@ -189,13 +244,12 @@ macro_rules! impl_common_ops_for_newtype_uint(
impl OptionCheckedAdd for $name {
type Output = Self;
fn opt_checked_add(
self,
rhs: Self,
) -> Result<Option<Self::Output>, opt_ops::CheckedError> {
) -> Result<Option<Self::Output>, opt_ops::Error> {
self.checked_add(rhs)
.ok_or(opt_ops::CheckedError::Overflow)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
}
}
@ -222,14 +276,74 @@ macro_rules! impl_common_ops_for_newtype_uint(
}
}
impl OptionCheckedDiv<$inner_type> for $name {
type Output = Self;
fn opt_checked_div(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 {
return Err(opt_ops::Error::DivisionByZero);
}
self.0
.checked_div(rhs)
.ok_or(opt_ops::Error::Overflow)
.map(|val| Some(Self(val)))
}
}
impl OptionCheckedMul<$inner_type> for $name {
type Output = Self;
fn opt_checked_mul(
self,
rhs: $inner_type,
) -> Result<Option<Self::Output>, opt_ops::Error> {
self.checked_mul(rhs)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
}
}
impl OptionSaturatingMul<$inner_type> for $name {
type Output = Self;
fn opt_saturating_mul(self, rhs: $inner_type) -> Option<Self::Output> {
Some(self.saturating_mul(rhs))
}
}
impl OptionOverflowingMul<$inner_type> for $name {
type Output = Self;
fn opt_overflowing_mul(self, rhs: $inner_type) -> Option<(Self::Output, bool)> {
let res = self.overflowing_mul(rhs);
Some((res.0, res.1))
}
}
impl OptionWrappingMul<$inner_type> for $name {
type Output = Self;
fn opt_wrapping_mul(self, rhs: $inner_type) -> Option<Self::Output> {
Some(self.wrapping_mul(rhs))
}
}
impl OptionCheckedRem<$inner_type> for $name {
type Output = Self;
fn opt_checked_rem(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 {
return Err(opt_ops::Error::DivisionByZero);
}
self.0
.checked_rem(rhs)
.ok_or(opt_ops::Error::Overflow)
.map(|val| Some(Self(val)))
}
}
impl OptionCheckedSub for $name {
type Output = Self;
fn opt_checked_sub(
self,
rhs: Self,
) -> Result<Option<Self::Output>, opt_ops::CheckedError> {
) -> Result<Option<Self::Output>, opt_ops::Error> {
self.checked_sub(rhs)
.ok_or(opt_ops::CheckedError::Overflow)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
}
}