use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use num_traits::One;
use crate::non_zero::{NonZero, NonZeroSign};
use crate::Signed;
pub trait NonZeroFactorizable: NonZero + Clone {
type Factor: NonZero + Eq + PartialEq + Ord + PartialOrd + Hash + Clone + Debug;
type Power: Add<Output=Self::Power> + AddAssign + Sub<Output=Self::Power> + SubAssign + One + Signed + Eq + Copy + Clone + Debug;
type Residual: FactorizationResidual;
fn factorize(&self) -> NonZeroFactorization<Self::Factor, Self::Power, Self::Residual>;
}
pub trait FactorizationResidual: Eq + Clone + Debug {
fn one() -> Self;
fn is_one(&self) -> bool;
}
macro_rules! residual_from_num_traits_one {
($($ty:ty)*) => {
$(
impl FactorizationResidual for $ty {
#[inline]
fn one() -> Self {
<$ty as One>::one()
}
#[inline]
fn is_one(&self) -> bool {
<$ty as One>::is_one(self)
}
}
)*
}
}
residual_from_num_traits_one!(u8 u16 u32 u64 u128 usize);
impl<Numerator, Denominator> FactorizationResidual for (Numerator, Denominator)
where
Numerator: FactorizationResidual,
Denominator: FactorizationResidual,
{
#[inline]
fn one() -> Self {
(Numerator::one(), Denominator::one())
}
#[inline]
fn is_one(&self) -> bool {
self.0.is_one() && self.1.is_one()
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct NonZeroFactorization<Factor, Power, Residual> {
pub sign: NonZeroSign,
pub factors: Vec<(Factor, Power)>,
pub residual: Residual,
}
impl<Factor, Power, Residual: FactorizationResidual> NonZeroFactorization<Factor, Power, Residual> {
#[must_use]
#[inline]
pub fn is_complete(&self) -> bool {
self.residual.is_one()
}
}