const-modulo-ring 0.1.1

Z/mZ for const modulo m
Documentation
use core::{
    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
    str::FromStr,
};
macro_rules! generate {
    ($name: ident, $base:ty, $wide:ty, $signed_wide: ty, $num_traits: ident, $test_name: ident) => {
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        pub struct $name<const M: $base>($base);

        impl<const M: $base> From<$base> for $name<M> {
            fn from(x: $base) -> Self {
                Self(x % M)
            }
        }
        #[auto_impl_ops::auto_ops]
        impl<const M: $base> AddAssign<&$name<M>> for $name<M> {
            fn add_assign(&mut self, other: &Self) {
                let t = self.0 + other.0;
                self.0 = if t >= M { t - M } else { t };
            }
        }
        #[auto_impl_ops::auto_ops]
        impl<const M: $base> SubAssign<&$name<M>> for $name<M> {
            fn sub_assign(&mut self, other: &Self) {
                let t = self.0 + (M - other.0);
                self.0 = if t >= M { t - M } else { t };
            }
        }
        impl<const M: $base> Neg for $name<M> {
            type Output = Self;
            fn neg(self) -> Self::Output {
                Self(M - self.0)
            }
        }
        impl<const M: $base> Neg for &$name<M> {
            type Output = $name<M>;
            fn neg(self) -> Self::Output {
                $name(M - self.0)
            }
        }
        #[auto_impl_ops::auto_ops]
        impl<const M: $base> MulAssign<&$name<M>> for $name<M> {
            fn mul_assign(&mut self, other: &Self) {
                self.0 = ((self.0 as $wide) * (other.0 as $wide) % (M as $wide)) as $base;
            }
        }
        #[auto_impl_ops::auto_ops]
        impl<const M: $base> DivAssign<&$name<M>> for $name<M> {
            fn div_assign(&mut self, other: &Self) {
                let t = ring_algorithm::modulo_division(
                    self.0 as $signed_wide,
                    other.0 as $signed_wide,
                    M as $signed_wide,
                )
                .expect("Can't divide");
                let t = if t < 0 { t + M as $signed_wide } else { t };
                self.0 = t as $base;
            }
        }
        impl<const M: $base> FromStr for $name<M> {
            type Err = std::num::ParseIntError;
            fn from_str(s: &str) -> Result<Self, Self::Err> {
                let mut v = s.parse::<i128>()?;
                v %= M as i128;
                if v < 0 {
                    v += M as i128;
                }
                Ok(Self(v as $base))
            }
        }
        impl<const M: $base> std::fmt::Display for $name<M> {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
                write!(f, "{}", self.0)
            }
        }

        #[cfg(feature = "num-traits")]
        mod $num_traits {
            use crate::$name;
            use num_traits::{ConstOne, ConstZero, One, Zero};
            impl<const M: $base> Zero for $name<M> {
                fn zero() -> Self {
                    Self::ZERO
                }
                fn is_zero(&self) -> bool {
                    *self == Self::ZERO
                }
            }
            impl<const M: $base> ConstZero for $name<M> {
                const ZERO: Self = Self(0);
            }
            impl<const M: $base> One for $name<M> {
                fn one() -> Self {
                    Self::ONE
                }
            }
            impl<const M: $base> ConstOne for $name<M> {
                const ONE: Self = Self(1);
            }
        }
        #[cfg(test)]
        mod $test_name {
            use super::*;
            #[test]
            fn add() {
                let a = $name::<6>(2);
                let b = $name::<6>(3);
                let c = $name::<6>(4);
                let d = $name::<6>(5);
                let e = $name::<6>(1);
                let f = $name::<6>(0);
                assert_eq!(a + b, d);
                assert_eq!(b + c, e);
                assert_eq!(b + b, f);
            }
            #[test]
            fn sub() {
                let a = $name::<6>(3);
                let b = $name::<6>(2);
                let c = $name::<6>(4);
                let d = $name::<6>(1);
                let e = $name::<6>(4);
                let f = $name::<6>(0);
                assert_eq!(a - b, d);
                assert_eq!(b - c, e);
                assert_eq!(a - a, f);
            }
            #[test]
            fn mul() {
                let a = $name::<6>(2);
                let b = $name::<6>(5);
                let c = $name::<6>(3);
                let d = $name::<6>(4);
                let e = $name::<6>(3);
                let f = $name::<6>(0);
                assert_eq!(a * b, d);
                assert_eq!(b * c, e);
                assert_eq!(a * c, f);
            }
            #[test]
            fn div() {
                let a = $name::<5>(2);
                let b = $name::<5>(3);
                let c = $name::<5>(4);
                let d = $name::<5>(4);
                let e = $name::<5>(2);
                let f = $name::<5>(3);
                assert_eq!(a / b, d);
                assert_eq!(b / c, e);
                assert_eq!(a / c, f);
            }
        }
    };
}
generate!(ConstModulo8, u8, u16, i16, impl_num_traits8, test8);
generate!(ConstModulo16, u16, u32, i32, impl_num_traits16, test16);
generate!(ConstModulo32, u32, u64, i64, impl_num_traits32, test32);
generate!(ConstModulo64, u64, u128, i128, impl_num_traits64, test64);