extern crate num_traits;
use std::ops::*;
use std::cmp::PartialEq;
use num_traits::ops::checked::*;
#[macro_export]
macro_rules! let_checked {
($($ident:ident),*) => {$(
let $ident = $crate::Checker(Some($ident));
)*};
($($ident:ident,)*) => {$(
let $ident = $crate::Checker(Some($ident));
)*};
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Checker<T>( #[doc(hidden)] pub Option<T>);
impl<T> Deref for Checker<T> {
type Target = Option<T>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl<T> DerefMut for Checker<T> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl<T> PartialEq<T> for Checker<T>
where T: PartialEq<T> + Copy
{
fn eq(&self, other: &T) -> bool {
self.0 == Some(*other)
}
}
impl<T> PartialEq<Option<T>> for Checker<T>
where T: PartialEq<T>
{
fn eq(&self, other: &Option<T>) -> bool {
&self.0 == other
}
}
macro_rules! impl_checked {
($Vanilla:ident, $vanilla_fn:ident, $Checked:ident, $checked_fn:ident) => {
impl<T> $Vanilla<Self> for Checker<T>
where T: $Checked
{
type Output = Self;
#[inline]
fn $vanilla_fn(self, rhs: Checker<T>) -> Self {
if let (Some(l), Some(r)) = (self.0, rhs.0) {
Checker(l.$checked_fn(&r))
} else {
Checker(None)
}
}
}
impl<T> $Vanilla<T> for Checker<T>
where T: $Checked
{
type Output = Self;
#[inline]
fn $vanilla_fn(self, rhs: T) -> Self {
Checker(self.0.and_then(|l| l.$checked_fn(&rhs)))
}
}
}
}
impl_checked![Add, add, CheckedAdd, checked_add];
impl_checked![Sub, sub, CheckedSub, checked_sub];
impl_checked![Mul, mul, CheckedMul, checked_mul];
impl_checked![Div, div, CheckedDiv, checked_div];
#[cfg(test)]
mod test {
#[test]
fn compiles() {
let a = 10;
let_checked![a];
let _ = a + a;
let _ = a - a;
let _ = a * a;
let _ = a / a;
let _ = a + 1;
let _ = a - 1;
let _ = a * 1;
let _ = a / 1;
}
#[test]
fn divide_by_zero() {
let b = 1u8;
let z = 0u8;
let_checked![b, z, ];
assert_eq!(b / z, None);
}
#[test]
fn empty_invoke() {
let_checked![]; }
}