use std::{i8, i16, i32, i64, isize};
use std::error::Error;
use std::fmt::{self, Display, Formatter};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IntOverflow;
const INT_OVERFLOW_STR: &'static str = "integer overflow";
impl Display for IntOverflow {
fn fmt (&self, f: &mut Formatter) -> fmt::Result {
f.write_str(INT_OVERFLOW_STR)
}
}
impl Error for IntOverflow {
fn description (&self) -> &str { INT_OVERFLOW_STR }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IntUnderflow;
const INT_UNDERFLOW_STR: &'static str = "integer underflow";
impl Display for IntUnderflow {
fn fmt (&self, f: &mut Formatter) -> fmt::Result {
f.write_str(INT_UNDERFLOW_STR)
}
}
impl Error for IntUnderflow {
fn description (&self) -> &str { INT_UNDERFLOW_STR }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum IntRangeError {
Overflow,
Underflow,
}
impl IntRangeError {
fn as_str (self) -> &'static str {
match self {
IntRangeError::Overflow => INT_OVERFLOW_STR,
IntRangeError::Underflow => INT_UNDERFLOW_STR,
}
}
}
impl Display for IntRangeError {
fn fmt (&self, f: &mut Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl Error for IntRangeError {
fn description (&self) -> &str { self.as_str() }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DivideByZero;
const DIVIDE_BY_ZERO_STR: &'static str = "divide by zero";
impl Display for DivideByZero {
fn fmt (&self, f: &mut Formatter) -> fmt::Result {
f.write_str(DIVIDE_BY_ZERO_STR)
}
}
impl Error for DivideByZero {
fn description (&self) -> &str { DIVIDE_BY_ZERO_STR }
}
pub trait TryAdd<RHS = Self> {
type Output;
type Err;
fn try_add (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_add_unsigned {
($($ty:ty),*) => { $(
impl TryAdd for $ty {
type Output = $ty;
type Err = IntOverflow;
fn try_add (self, rhs: $ty) -> Result<$ty, IntOverflow> {
match self.checked_add(rhs) {
None => Err(IntOverflow),
Some(n) => Ok(n),
}
}
}
)* };
}
macro_rules! impl_try_add_signed {
($($ty:ty),*) => { $(
impl TryAdd for $ty {
type Output = $ty;
type Err = IntRangeError;
fn try_add (self, rhs: $ty) -> Result<$ty, IntRangeError> {
match self.checked_add(rhs) {
None => {
if rhs > 0 {
Err(IntRangeError::Overflow)
} else {
Err(IntRangeError::Underflow)
}
},
Some(n) => Ok(n),
}
}
}
)* };
}
impl_try_add_unsigned!(u8, u16, u32, u64, usize);
impl_try_add_signed!(i8, i16, i32, i64, isize);
#[test]
fn test_try_add () {
assert_eq!(254u8.try_add(1), Ok(255u8));
assert_eq!(255u8.try_add(1), Err(IntOverflow));
assert_eq!(126i8.try_add(1), Ok(127i8));
assert_eq!(127i8.try_add(1), Err(IntRangeError::Overflow));
assert_eq!((-127i8).try_add(-1), Ok(-128i8));
assert_eq!((-128i8).try_add(-1), Err(IntRangeError::Underflow));
}
pub trait TrySub<RHS = Self> {
type Output;
type Err;
fn try_sub (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_sub_unsigned {
($($ty:ty),*) => { $(
impl TrySub for $ty {
type Output = $ty;
type Err = IntUnderflow;
fn try_sub (self, rhs: $ty) -> Result<$ty, IntUnderflow> {
match self.checked_sub(rhs) {
None => Err(IntUnderflow),
Some(n) => Ok(n),
}
}
}
)* };
}
macro_rules! impl_try_sub_signed {
($($ty:ty),*) => { $(
impl TrySub for $ty {
type Output = $ty;
type Err = IntRangeError;
fn try_sub (self, rhs: $ty) -> Result<$ty, IntRangeError> {
match self.checked_sub(rhs) {
None => {
if rhs > 0 {
Err(IntRangeError::Underflow)
} else {
Err(IntRangeError::Overflow)
}
},
Some(n) => Ok(n),
}
}
}
)* };
}
impl_try_sub_unsigned!(u8, u16, u32, u64, usize);
impl_try_sub_signed!(i8, i16, i32, i64, isize);
#[test]
fn test_try_sub () {
assert_eq!(1u8.try_sub(1), Ok(0u8));
assert_eq!(0u8.try_sub(1), Err(IntUnderflow));
assert_eq!((-127i8).try_sub(1), Ok(-128i8));
assert_eq!((-128i8).try_sub(1), Err(IntRangeError::Underflow));
assert_eq!(126i8.try_sub(-1), Ok(127i8));
assert_eq!(127i8.try_sub(-1), Err(IntRangeError::Overflow));
}
pub trait TryMul<RHS = Self> {
type Output;
type Err;
fn try_mul (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_mul_unsigned {
($($ty:ty),*) => { $(
impl TryMul for $ty {
type Output = $ty;
type Err = IntOverflow;
fn try_mul (self, rhs: $ty) -> Result<$ty, IntOverflow> {
match self.checked_mul(rhs) {
None => Err(IntOverflow),
Some(n) => Ok(n),
}
}
}
)* };
}
macro_rules! impl_try_mul_signed {
($($ty:ty),*) => { $(
impl TryMul for $ty {
type Output = $ty;
type Err = IntRangeError;
fn try_mul (self, rhs: $ty) -> Result<$ty, IntRangeError> {
match self.checked_mul(rhs) {
None => {
if (self > 0) == (rhs > 0) {
Err(IntRangeError::Overflow)
} else {
Err(IntRangeError::Underflow)
}
},
Some(n) => Ok(n),
}
}
}
)* };
}
impl_try_mul_unsigned!(u8, u16, u32, u64, usize);
impl_try_mul_signed!(i8, i16, i32, i64, isize);
#[test]
fn test_try_mul () {
assert_eq!(85u8.try_mul(3), Ok(255u8));
assert_eq!(64u8.try_mul(4), Err(IntOverflow));
assert_eq!(63i8.try_mul(2), Ok(126i8));
assert_eq!(64i8.try_mul(2), Err(IntRangeError::Overflow));
assert_eq!(64i8.try_mul(-2), Ok(-128i8));
assert_eq!(65i8.try_mul(-2), Err(IntRangeError::Underflow));
assert_eq!((-64i8).try_mul(2), Ok(-128i8));
assert_eq!((-65i8).try_mul(2), Err(IntRangeError::Underflow));
assert_eq!((-63i8).try_mul(-2), Ok(126i8));
assert_eq!((-64i8).try_mul(-2), Err(IntRangeError::Overflow));
}
pub trait TryDiv<RHS = Self> {
type Output;
type Err;
fn try_div (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_div {
($($ty:ty),*) => { $(
impl TryDiv for $ty {
type Output = $ty;
type Err = DivideByZero;
fn try_div (self, rhs: $ty) -> Result<$ty, DivideByZero> {
if rhs == 0 {
Err(DivideByZero)
} else {
Ok(self / rhs)
}
}
}
)* };
}
impl_try_div!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
#[test]
fn test_try_div () {
assert_eq!(255u8.try_div(3), Ok(85u8));
assert_eq!(255u8.try_div(0), Err(DivideByZero));
}
pub trait TryRem<RHS = Self> {
type Output;
type Err;
fn try_rem (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_rem {
($($ty:ty),*) => { $(
impl TryRem for $ty {
type Output = $ty;
type Err = DivideByZero;
fn try_rem (self, rhs: $ty) -> Result<$ty, DivideByZero> {
if rhs == 0 {
Err(DivideByZero)
} else {
Ok(self % rhs)
}
}
}
)* };
}
impl_try_rem!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
#[test]
fn test_try_rem () {
assert_eq!(11u8.try_rem(5), Ok(1u8));
assert_eq!(11u8.try_rem(0), Err(DivideByZero));
}
pub trait TryNeg {
type Output;
type Err;
fn try_neg (self) -> Result<Self::Output, Self::Err>;
}
macro_rules! impl_try_neg {
($($ty:ident),*) => { $(
impl TryNeg for $ty {
type Output = $ty;
type Err = IntOverflow;
fn try_neg (self) -> Result<$ty, IntOverflow> {
if self == $ty::MIN {
Err(IntOverflow)
} else {
Ok(-self)
}
}
}
)* };
}
impl_try_neg!(i8, i16, i32, i64, isize);
#[test]
fn test_try_neg () {
assert_eq!((-127i8).try_neg(), Ok(127i8));
assert_eq!((-128i8).try_neg(), Err(IntOverflow));
}