use crate::number::traits::{ConstZero, Numbers};
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
use devela::convert::az::CheckedAs;
#[cfg(not(feature = "std"))]
use crate::all::is_prime;
#[cfg(feature = "std")]
use crate::all::is_prime_sieve;
pub trait Integers: Numbers {
fn integer_is_even(&self) -> bool;
fn integer_is_odd(&self) -> bool {
!self.integer_is_even()
}
fn integer_is_multiple_of(&self, other: &Self) -> bool;
fn integer_is_divisor_of(&self, other: &Self) -> bool {
other.integer_is_multiple_of(self)
}
fn integer_is_prime(&self) -> Option<bool>;
#[rustfmt::skip]
#[must_use]
fn integer_gcd(&self, other: &Self) -> Option<Self> where Self: Sized;
#[rustfmt::skip]
#[must_use]
fn integer_lcm(&self, other: &Self) -> Option<Self> where Self: Sized;
#[must_use]
fn integer_digits(&self) -> usize;
}
macro_rules! impl_integer {
(many $($t:ident),+) => { $( impl_integer![$t]; )+ };
($t:ident) => {
impl Integers for $t {
#[inline]
fn integer_is_even(&self) -> bool {
*self & 1 == 0
}
#[inline]
fn integer_is_multiple_of(&self, other: &Self) -> bool {
*self % *other == 0
}
#[inline]
fn integer_is_prime(&self) -> Option<bool> {
#[cfg(feature = "std")]
return Some(is_prime_sieve((*self).checked_as::<usize>()?));
#[cfg(not(feature = "std"))]
return Some(is_prime((*self).checked_as::<u32>()?));
}
#[inline]
fn integer_gcd(&self, other: &Self) -> Option<Self> {
let (mut a, mut b) = (*self, *other);
while b != Self::ZERO {
let temp = b;
b = a % b;
a = temp;
}
Some(a)
}
#[inline]
fn integer_lcm(&self, other: &Self) -> Option<Self> {
Some(*self * *other / self.integer_gcd(other).unwrap())
}
fn integer_digits(&self) -> usize {
self.checked_ilog10().unwrap_or(0) as usize
}
}
};
(many_nonzero $($t:ident),+) => { $( impl_integer![nonzero $t]; )+ };
(nonzero $t:ident) => {
impl Integers for $t {
#[inline]
fn integer_is_even(&self) -> bool {
self.get() & 1 == 0
}
#[inline]
fn integer_is_multiple_of(&self, other: &Self) -> bool {
self.get() % other.get() == 0
}
#[inline]
fn integer_is_prime(&self) -> Option<bool> {
#[cfg(feature = "std")]
return Some(is_prime_sieve(self.get().checked_as::<usize>()?));
#[cfg(not(feature = "std"))]
return Some(is_prime(self.get().checked_as::<u32>()?));
}
#[inline]
fn integer_gcd(&self, other: &Self) -> Option<Self> {
let (mut a, mut b) = (self.get(), other.get());
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
Some($t::new(a).unwrap())
}
#[inline]
fn integer_lcm(&self, other: &Self) -> Option<Self> {
Some($t::new(
self.get() * other.get() / self.get().integer_gcd(&other.get()).unwrap()
).unwrap())
}
fn integer_digits(&self) -> usize {
self.get().ilog10().try_into().expect("more than usize::MAX digits")
}
}
};
}
impl_integer![many i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize];
impl_integer![many_nonzero
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize
];