//! Number traits and utilities. use core::{ mem, ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign, }, }; pub mod rational; //NOTE: these should probably be broken up a bunch; they're only implemented // this way because i didn't really need much else to implement // rationals. ideally we should break them up on the lines of rings, // groups, fields, unique factorization domains, principal ideal domains, // ordered rings, etc. this would make further extensions to // functionality in azimuth easier. /// Integer. pub trait Integer: Eq + Ord + Mul + Div + Add + Sub + Rem + MulAssign + DivAssign + AddAssign + SubAssign + RemAssign + Sized + Copy + Clone { //NOTE: `Neg` is neglected here as the primary purpose of this trait is // to abstract over integers for the `Rational` type. as stated // above, i'd like to adjust the way all of this works anyway for // future extensions, but for now, we don't really need it. //NOTE: `Copy` is required for now as bignum support is not a requirement // yet and this makes implementation simpler. /// Additive identity. const ZERO: Self; /// Multiplicative identity. const ONE: Self; /// Maximum attainable value. const MAX: Self; /// Minimum attainable value. const MIN: Self; /// Calculates the greatest common divisor of this number and another fn gcd(&self, rhs: &Self) -> Self; } /// Helper macro for the implementation of `Integer` macro_rules! integer_impl { ($type:ty, $zero:expr, $one:expr, $max:expr, $min:expr) => { impl Integer for $type { const ZERO: Self = $zero; const ONE: Self = $one; const MAX: Self = $max; const MIN: Self = $min; #[inline] fn gcd(&self, rhs: &Self) -> Self { let mut m = *self; let mut n = *rhs; if m < n { mem::swap(&mut m, &mut n); } while n != 0 { let t = n; n = m % n; m = t; } m } } }; } integer_impl!(i8, 0, 1, i8::MAX, i8::MIN); integer_impl!(i16, 0, 1, i16::MAX, i16::MIN); integer_impl!(i32, 0, 1, i32::MAX, i32::MIN); integer_impl!(i64, 0, 1, i64::MAX, i64::MIN); integer_impl!(i128, 0, 1, i128::MAX, i128::MIN); integer_impl!(u8, 0, 1, u8::MAX, u8::MIN); integer_impl!(u16, 0, 1, u16::MAX, u16::MIN); integer_impl!(u32, 0, 1, u32::MAX, u32::MIN); integer_impl!(u64, 0, 1, u64::MAX, u64::MIN); integer_impl!(u128, 0, 1, u128::MAX, u128::MIN);