modint 0.1.1

Modular arithmetic integer
Documentation
extern crate typenum;
extern crate num_traits;

use typenum::Unsigned as CompileTimeUnsigned;
use num_traits::ops::wrapping::{
    WrappingAdd,
    WrappingMul
};
use num_traits::{
    Num, 
    Zero, 
    One, 
    Unsigned as UnsignedNum
};

use std::marker::PhantomData;
use std::ops::{
    Add,
    Sub,
    Mul,
    Div,
    Rem,
};

pub trait FromCompileTimeUnsinged {
    fn from<T: CompileTimeUnsigned>() -> Self;
}

impl FromCompileTimeUnsinged for u8 {
    fn from<T: CompileTimeUnsigned>() -> Self {
        T::to_u8()
    }
}

impl FromCompileTimeUnsinged for u16 {
    fn from<T: CompileTimeUnsigned>() -> Self {
        T::to_u16()
    }
}

impl FromCompileTimeUnsinged for u32 {
    fn from<T: CompileTimeUnsigned>() -> Self {
        T::to_u32()
    }
}

impl FromCompileTimeUnsinged for u64 {
    fn from<T: CompileTimeUnsigned>() -> Self {
        T::to_u64()
    }
}

impl FromCompileTimeUnsinged for usize {
    fn from<T: CompileTimeUnsigned>() -> Self {
        T::to_usize()
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct Unsigned<V, M> {
    value: V,
    phantom: PhantomData<M>
}

impl<V, M> Unsigned<V, M> {
    pub fn value(self) -> V {
        self.value
    }
}

impl<V, M> From<V> for Unsigned<V, M>
    where V: Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    fn from(value: V) -> Self {
        Unsigned {
            value: value % V::from::<M>(),
            phantom: Default::default()
        }

    }
}

impl<V, M> Add for Unsigned<V, M>
    where V: WrappingAdd + Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Unsigned {
            value: self.value.wrapping_add(&rhs.value) % V::from::<M>(),
            phantom: Default::default()
        }
    }
}

impl<V, M> Sub for Unsigned<V, M>
    where V: Sub<Output=V> + Ord + Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        let value = if self.value >= rhs.value {
            self.value - rhs.value
        } else {
            V::from::<M>() - (rhs.value - self.value)
        };

        Unsigned {
            value,
            phantom: Default::default()
        }
    }
}

impl<V, M> Mul for Unsigned<V, M>
    where V: WrappingMul + Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        Unsigned {
            value: self.value.wrapping_mul(&rhs.value) % V::from::<M>(),
            phantom: Default::default()
        }
    }
}

impl<V, M> Div for Unsigned<V, M>
    where V: Div<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    type Output = Self;

    fn div(self, rhs: Self) -> Self {
        Unsigned {
            value: self.value / rhs.value,
            phantom: Default::default()
        }
    }
}

impl<V, M> Rem for Unsigned<V, M>
    where V: Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    type Output = Self;

    fn rem(self, rhs: Self) -> Self {
        Unsigned {
            value: self.value % rhs.value,
            phantom: Default::default()
        }
    }
}

impl<V, M> Zero for Unsigned<V, M>
    where V: Zero + WrappingAdd + Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    fn zero() -> Self {
        Unsigned {
            value: V::zero(),
            phantom: Default::default()
        }
    }

    fn is_zero(&self) -> bool {
        self.value.is_zero()
    }
}

impl<V, M> One for Unsigned<V, M>
    where V: One + WrappingMul + Rem<Output=V> + FromCompileTimeUnsinged,
          M: CompileTimeUnsigned
{
    fn one() -> Self {
        V::one().into()
    }
}

impl<V, M> Num for Unsigned<V, M>
    where V: Num + FromCompileTimeUnsinged + WrappingAdd + WrappingMul + PartialEq + Ord,
          M: CompileTimeUnsigned + PartialEq
{
    type FromStrRadixErr = <V as Num>::FromStrRadixErr;

    fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
        Ok(V::from_str_radix(s, radix)?.into())
    }
}

impl<V, M> UnsignedNum for Unsigned<V, M>
    where V: Num + FromCompileTimeUnsinged + WrappingAdd + WrappingMul + PartialEq + Ord,
          M: CompileTimeUnsigned + PartialEq
{}

#[cfg(test)]
mod tests {
    use typenum::U17;
    use super::Unsigned;

    type M17 = Unsigned<u8, U17>;

    #[test]
    fn construct() {
        assert_eq!(M17::from(1 ).value(), 1);
        assert_eq!(M17::from(4 ).value(), 4);
        assert_eq!(M17::from(17).value(), 0);
        assert_eq!(M17::from(18).value(), 1);
    }

    #[test]
    fn add() {
        assert_eq!(M17::from(1)  + 1 .into(), 2.into());
        assert_eq!(M17::from(16) + 1 .into(), 0.into());
        assert_eq!(M17::from(1)  + 17.into(), 1.into());
        assert_eq!(M17::from(1)  + 35.into(), 2.into());
    }

    #[test]
    fn sub() {
        assert_eq!(M17::from(2)  - 1 .into(), 1 .into());
        assert_eq!(M17::from(1)  - 3 .into(), 15.into());
        assert_eq!(M17::from(15) - 16.into(), 16.into());
        assert_eq!(M17::from(11) - 17.into(), 11.into());
    }

    #[test]
    fn mul() {
        assert_eq!(M17::from(2) * 2.into(), 4.into());
        assert_eq!(M17::from(5) * 4.into(), 3.into());
    }
}