use core::marker::PhantomData;
use core::ops::Add;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Zero;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Succ<N>(PhantomData<N>);
impl<N> Succ<N> {
pub const fn new() -> Self {
Succ(PhantomData)
}
}
pub type N1 = Succ<Zero>;
pub type N2 = Succ<N1>;
pub type N3 = Succ<N2>;
pub type N4 = Succ<N3>;
pub type N5 = Succ<N4>;
pub type N6 = Succ<N5>;
pub type N7 = Succ<N6>;
pub type N8 = Succ<N7>;
pub type N9 = Succ<N8>;
pub type N10 = Succ<N9>;
pub trait Naturalis {
const VALUE: usize;
#[inline]
fn value() -> usize {
Self::VALUE
}
}
impl Naturalis for Zero {
const VALUE: usize = 0;
}
impl<N: Naturalis> Naturalis for Succ<N> {
const VALUE: usize = N::VALUE + 1;
}
pub trait NonNihil: Naturalis {}
impl<N> NonNihil for Succ<N> where Succ<N>: Naturalis {}
pub trait Additio<M>: Naturalis {
type Summa: Naturalis;
}
impl<M: Naturalis> Additio<M> for Zero {
type Summa = M;
}
impl<N: Naturalis + Additio<M>, M: Naturalis> Additio<M> for Succ<N>
where
<N as Additio<M>>::Summa: Naturalis,
{
type Summa = Succ<<N as Additio<M>>::Summa>;
}
pub trait Multiplicatio<M>: Naturalis {
type Productum: Naturalis;
}
impl<M: Naturalis> Multiplicatio<M> for Zero {
type Productum = Zero;
}
impl<N, M> Multiplicatio<M> for Succ<N>
where
N: Naturalis + Multiplicatio<M>,
M: Naturalis + Additio<<N as Multiplicatio<M>>::Productum>,
<N as Multiplicatio<M>>::Productum: Naturalis,
<M as Additio<<N as Multiplicatio<M>>::Productum>>::Summa: Naturalis,
{
type Productum = <M as Additio<<N as Multiplicatio<M>>::Productum>>::Summa;
}
pub trait Minor<M>: Naturalis {}
impl<M: Naturalis> Minor<Succ<M>> for Zero {}
impl<N: Naturalis + Minor<M>, M: Naturalis> Minor<Succ<M>> for Succ<N> {}
pub trait MinorVelAequus<M>: Naturalis {}
impl<M: Naturalis> MinorVelAequus<M> for Zero {}
impl<N: Naturalis + MinorVelAequus<M>, M: Naturalis> MinorVelAequus<Succ<M>> for Succ<N> {}
pub trait Maior<M>: Naturalis {}
impl<N: Naturalis> Maior<Zero> for Succ<N> {}
impl<N: Naturalis + Maior<M>, M: Naturalis> Maior<Succ<M>> for Succ<N> {}
pub trait Aequus<M>: Naturalis {}
impl Aequus<Zero> for Zero {}
impl<N: Naturalis + Aequus<M>, M: Naturalis> Aequus<Succ<M>> for Succ<N> {}
pub trait Praecessor: NonNihil {
type Prior: Naturalis;
}
impl<N: Naturalis> Praecessor for Succ<N> {
type Prior = N;
}
pub trait Subtractio<M>: Naturalis {
type Differentia: Naturalis;
}
impl<N: Naturalis> Subtractio<Zero> for N {
type Differentia = N;
}
impl<M: Naturalis> Subtractio<Succ<M>> for Zero {
type Differentia = Zero;
}
impl<N, M> Subtractio<Succ<M>> for Succ<N>
where
N: Naturalis + Subtractio<M>,
M: Naturalis,
{
type Differentia = <N as Subtractio<M>>::Differentia;
}
pub trait Minimus<M>: Naturalis {
type Min: Naturalis;
}
impl<M: Naturalis> Minimus<M> for Zero {
type Min = Zero;
}
impl<N: Naturalis> Minimus<Zero> for Succ<N> {
type Min = Zero;
}
impl<N, M> Minimus<Succ<M>> for Succ<N>
where
N: Naturalis + Minimus<M>,
M: Naturalis,
<N as Minimus<M>>::Min: Naturalis,
{
type Min = Succ<<N as Minimus<M>>::Min>;
}
pub trait Maximus<M>: Naturalis {
type Max: Naturalis;
}
impl<M: Naturalis> Maximus<M> for Zero {
type Max = M;
}
impl<N: Naturalis> Maximus<Zero> for Succ<N> {
type Max = Succ<N>;
}
impl<N, M> Maximus<Succ<M>> for Succ<N>
where
N: Naturalis + Maximus<M>,
M: Naturalis,
<N as Maximus<M>>::Max: Naturalis,
{
type Max = Succ<<N as Maximus<M>>::Max>;
}
pub type Sum<A, B> = <A as Additio<B>>::Summa;
pub type Prod<A, B> = <A as Multiplicatio<B>>::Productum;
pub type Diff<A, B> = <A as Subtractio<B>>::Differentia;
pub type Min<A, B> = <A as Minimus<B>>::Min;
pub type Max<A, B> = <A as Maximus<B>>::Max;
pub type Pred<N> = <N as Praecessor>::Prior;
impl Add<Zero> for Zero {
type Output = Zero;
#[inline]
fn add(self, _: Zero) -> Zero {
Zero
}
}
impl<N> Add<Succ<N>> for Zero {
type Output = Succ<N>;
#[inline]
fn add(self, rhs: Succ<N>) -> Succ<N> {
rhs
}
}
impl<N, M> Add<M> for Succ<N>
where
N: Add<M>,
{
type Output = Succ<N::Output>;
#[inline]
fn add(self, _rhs: M) -> Self::Output {
Succ::new()
}
}
#[cfg(test)]
#[allow(clippy::extra_unused_type_parameters)]
mod tests {
use super::*;
#[test]
fn test_naturalis_value() {
assert_eq!(Zero::VALUE, 0);
assert_eq!(<N1 as Naturalis>::VALUE, 1);
assert_eq!(<N2 as Naturalis>::VALUE, 2);
assert_eq!(<N3 as Naturalis>::VALUE, 3);
assert_eq!(<N5 as Naturalis>::VALUE, 5);
assert_eq!(<N10 as Naturalis>::VALUE, 10);
}
#[test]
fn test_non_nihil() {
fn requires_non_zero<N: NonNihil>() -> usize {
N::VALUE
}
assert_eq!(requires_non_zero::<N1>(), 1);
assert_eq!(requires_non_zero::<N5>(), 5);
}
#[test]
fn test_additio() {
type ZeroPlusThree = Sum<Zero, N3>;
assert_eq!(<ZeroPlusThree as Naturalis>::VALUE, 3);
type TwoPlusThree = Sum<N2, N3>;
assert_eq!(<TwoPlusThree as Naturalis>::VALUE, 5);
type ThreePlusZero = Sum<N3, Zero>;
assert_eq!(<ThreePlusZero as Naturalis>::VALUE, 3);
}
#[test]
fn test_multiplicatio() {
type ZeroTimesFive = Prod<Zero, N5>;
assert_eq!(<ZeroTimesFive as Naturalis>::VALUE, 0);
type TwoTimesThree = Prod<N2, N3>;
assert_eq!(<TwoTimesThree as Naturalis>::VALUE, 6);
type ThreeTimesTwo = Prod<N3, N2>;
assert_eq!(<ThreeTimesTwo as Naturalis>::VALUE, 6);
}
#[test]
fn test_subtractio() {
type FiveMinusThree = Diff<N5, N3>;
assert_eq!(<FiveMinusThree as Naturalis>::VALUE, 2);
type ThreeMinusFive = Diff<N3, N5>;
assert_eq!(<ThreeMinusFive as Naturalis>::VALUE, 0);
type FiveMinusZero = Diff<N5, Zero>;
assert_eq!(<FiveMinusZero as Naturalis>::VALUE, 5);
}
#[test]
fn test_comparison_minor() {
fn is_less_than<N: Minor<M>, M>() -> bool {
true
}
assert!(is_less_than::<Zero, N1>());
assert!(is_less_than::<N2, N5>());
assert!(is_less_than::<Zero, N10>());
}
#[test]
fn test_comparison_maior() {
fn is_greater_than<N: Maior<M>, M>() -> bool {
true
}
assert!(is_greater_than::<N1, Zero>());
assert!(is_greater_than::<N5, N2>());
}
#[test]
fn test_comparison_aequus() {
fn is_equal<N: Aequus<M>, M>() -> bool {
true
}
assert!(is_equal::<Zero, Zero>());
assert!(is_equal::<N3, N3>());
assert!(is_equal::<N10, N10>());
}
#[test]
fn test_min_max() {
type MinThreeFive = Min<N3, N5>;
assert_eq!(<MinThreeFive as Naturalis>::VALUE, 3);
type MaxThreeFive = Max<N3, N5>;
assert_eq!(<MaxThreeFive as Naturalis>::VALUE, 5);
type MinZeroFive = Min<Zero, N5>;
assert_eq!(<MinZeroFive as Naturalis>::VALUE, 0);
type MaxZeroFive = Max<Zero, N5>;
assert_eq!(<MaxZeroFive as Naturalis>::VALUE, 5);
}
#[test]
fn test_praecessor() {
type PredFive = Pred<N5>;
assert_eq!(<PredFive as Naturalis>::VALUE, 4);
type PredOne = Pred<N1>;
assert_eq!(<PredOne as Naturalis>::VALUE, 0);
}
#[test]
fn test_ops_add() {
let _sum: Succ<Succ<Zero>> = Zero + Succ::<Succ<Zero>>::new();
let _sum2: Succ<Succ<Succ<Zero>>> = Succ::<Zero>::new() + Succ::<Succ<Zero>>::new();
}
#[test]
fn test_comparison_minor_vel_aequus() {
fn is_leq<N: MinorVelAequus<M>, M>() -> bool {
true
}
assert!(is_leq::<Zero, Zero>());
assert!(is_leq::<Zero, N1>());
assert!(is_leq::<Zero, N5>());
assert!(is_leq::<N2, N5>());
assert!(is_leq::<N3, N3>());
assert!(is_leq::<N5, N5>());
}
}