use core::fmt;
use core::hash::Hash;
use core::iter;
use core::ops;
pub trait IntegerOps
where
Self: Sized,
Self: ops::Add<Output = Self> + for<'a> ops::Add<&'a Self, Output = Self>,
Self: ops::Sub<Output = Self> + for<'a> ops::Sub<&'a Self, Output = Self>,
Self: ops::Mul<Output = Self> + for<'a> ops::Mul<&'a Self, Output = Self>,
Self: ops::Div<Output = Self> + for<'a> ops::Div<&'a Self, Output = Self>,
Self: ops::Neg<Output = Self>,
Self: ops::AddAssign<Self> + for<'a> ops::AddAssign<&'a Self>,
Self: ops::SubAssign<Self> + for<'a> ops::SubAssign<&'a Self>,
Self: ops::MulAssign<Self> + for<'a> ops::MulAssign<&'a Self>,
Self: ops::DivAssign<Self> + for<'a> ops::DivAssign<&'a Self>,
Self: ops::RemAssign<Self> + for<'a> ops::RemAssign<&'a Self>,
Self: iter::Sum<Self> + for<'a> iter::Sum<&'a Self>,
Self: iter::Product<Self> + for<'a> iter::Product<&'a Self>,
{
}
pub trait Integer
where
Self: Copy + Ord + Hash,
Self: fmt::Display,
Self: TryFrom<usize>,
Self: IntegerOps,
{
fn zero() -> Self;
fn one() -> Self;
fn two() -> Self;
fn div_euclid(self, rhs: Self) -> Self;
fn rem_euclid(self, rhs: Self) -> Self;
fn abs(self) -> Self;
fn signum(self) -> Self;
fn to_usize(self) -> usize
where
usize: TryFrom<Self>,
<usize as TryFrom<Self>>::Error: fmt::Debug,
{
usize::try_from(self).unwrap()
}
fn from_usize(n: usize) -> Self
where
<Self as TryFrom<usize>>::Error: fmt::Debug,
{
Self::try_from(n).unwrap()
}
}
#[doc(hidden)]
macro_rules! impl_integer {
($t:ty) => {
impl IntegerOps for $t {}
impl Integer for $t {
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn two() -> Self {
2
}
fn div_euclid(self, rhs: Self) -> Self {
<$t>::div_euclid(self, rhs)
}
fn rem_euclid(self, rhs: Self) -> Self {
<$t>::rem_euclid(self, rhs)
}
fn abs(self) -> Self {
<$t>::abs(self)
}
fn signum(self) -> Self {
<$t>::signum(self)
}
}
};
}
impl_integer!(i8);
impl_integer!(i16);
impl_integer!(i32);
impl_integer!(i64);
impl_integer!(i128);
impl_integer!(isize);
#[cfg(test)]
mod tests {
use crate::Integer;
#[test]
fn test_div_euclid_i32() {
assert_eq!(1, Integer::div_euclid(5_i32, 3));
assert_eq!(-2, Integer::div_euclid(-5_i32, 3));
}
#[test]
fn test_rem_euclid_i32() {
assert_eq!(2, Integer::rem_euclid(5_i32, 3));
assert_eq!(1, Integer::rem_euclid(-5_i32, 3));
}
#[test]
fn test_abs_i32() {
assert_eq!(5, Integer::abs(5_i32));
assert_eq!(5, Integer::abs(-5_i32));
}
#[test]
fn test_abs_i64() {
assert_eq!(5, Integer::abs(5_i64));
assert_eq!(5, Integer::abs(-5_i64));
}
#[test]
fn test_abs_i128() {
assert_eq!(5, Integer::abs(5_i128));
assert_eq!(5, Integer::abs(-5_i128));
}
#[test]
fn test_signum_i32() {
assert_eq!(1, Integer::signum(5_i32));
assert_eq!(0, Integer::signum(0_i32));
assert_eq!(-1, Integer::signum(-5_i32));
}
#[test]
fn test_signum_i64() {
assert_eq!(1, Integer::signum(5_i64));
assert_eq!(0, Integer::signum(0_i64));
assert_eq!(-1, Integer::signum(-5_i64));
}
#[test]
fn test_signum_i128() {
assert_eq!(1, Integer::signum(5_i128));
assert_eq!(0, Integer::signum(0_i128));
assert_eq!(-1, Integer::signum(-5_i128));
}
}