use crate::{Bit, Bit0, Bit1, Cons, Positive, Value};
pub trait Equal<Rhs>: Value {}
impl Equal<Bit0> for Bit0 {}
impl Equal<Bit1> for Bit1 {}
impl<B0: Bit, B1, S0: Positive, S1> Equal<Cons<B1, S1>> for Cons<B0, S0>
where
B1: Bit + Equal<B0>,
S1: Positive + Equal<S0>,
{
}
pub trait NotEqual<Rhs> {}
impl NotEqual<Bit0> for Bit1 {}
impl NotEqual<Bit1> for Bit0 {}
impl<B: Bit, S: Positive> NotEqual<Cons<B, S>> for Bit0 {}
impl<B: Bit, S: Positive> NotEqual<Cons<B, S>> for Bit1 {}
impl<B: Bit, S: Positive> NotEqual<Bit0> for Cons<B, S> {}
impl<B: Bit, S: Positive> NotEqual<Bit1> for Cons<B, S> {}
impl<S0: Positive, S1: Positive + NotEqual<S0>> NotEqual<Cons<Bit0, S1>> for Cons<Bit0, S0> {}
impl<S0: Positive, S1: Positive + NotEqual<S0>> NotEqual<Cons<Bit1, S1>> for Cons<Bit1, S0> {}
impl<S0: Positive, S1: Positive> NotEqual<Cons<Bit0, S1>> for Cons<Bit1, S0> {}
impl<S0: Positive, S1: Positive> NotEqual<Cons<Bit1, S1>> for Cons<Bit0, S0> {}
pub trait GreaterOrEqual<Rhs>: Value {}
pub trait LessOrEqual<Rhs>: Value {}
macro_rules! impl_ord {
(@ $name:ident [$($pnam:ident: ($($ptyp:tt$(<$tpar:ident>)*),+)),*] $typ0:ty, $typ1:ty) => {
impl<$($pnam: $($ptyp$(<$tpar>)*+)+ Sized),*> $name<$typ0> for $typ1 {}
};
($([$($pnam:ident: ($($ptyp:tt$(<$tpar:ident>)*),+)),*] $typ0:ty, $typ1:ty;)*) => {
$(
impl_ord!(@ GreaterOrEqual [$($pnam:($($ptyp$(<$tpar>)*),+)),*] $typ0, $typ1);
impl_ord!(@ LessOrEqual [$($pnam:($($ptyp$(<$tpar>)*),+)),*] $typ1, $typ0);
)*
};
}
impl_ord! {
[] Bit0, Bit0;
[] Bit0, Bit1;
[] Bit1, Bit1;
[B: (Bit), S: (Positive)] Bit0, Cons<B, S>;
[B: (Bit), S: (Positive)] Bit1, Cons<B, S>;
[S0: (Positive), S1: (Positive , GreaterOrEqual<S0> , NotEqual<S0>)]
Cons<Bit1, S0>, Cons<Bit0, S1>;
[S0: (Positive), S1: (Positive , GreaterOrEqual<S0>)]
Cons<Bit0, S0>, Cons<Bit0, S1>;
[S0: (Positive), S1: (Positive , GreaterOrEqual<S0>)]
Cons<Bit0, S0>, Cons<Bit1, S1>;
[S0: (Positive), S1: (Positive , GreaterOrEqual<S0>)]
Cons<Bit1, S0>, Cons<Bit1, S1>;
}
pub trait Compare<Rhs, BitL = (), BitR = (), BitC = ()>: Value {
type MAX: Value;
type MIN: Value;
#[doc(hidden)]
type BMAX;
#[doc(hidden)]
type BMIN;
}
impl<BL, BR, BC> Compare<Bit0, BL, BR, BC> for Bit0 {
type MAX = Bit0;
type MIN = Bit0;
type BMAX = BC;
type BMIN = BC;
}
impl<BL, BR, BC> Compare<Bit1, BL, BR, BC> for Bit0 {
type MAX = Bit1;
type MIN = Bit0;
type BMAX = BR;
type BMIN = BL;
}
impl<BL, BR, BC> Compare<Bit0, BL, BR, BC> for Bit1 {
type MAX = Bit1;
type MIN = Bit0;
type BMAX = BL;
type BMIN = BR;
}
impl<BL, BR, BC> Compare<Bit1, BL, BR, BC> for Bit1 {
type MAX = Bit1;
type MIN = Bit1;
type BMAX = BC;
type BMIN = BC;
}
impl<BL, BR, BC, B0: Bit, S0: Positive> Compare<Bit0, BL, BR, BC> for Cons<B0, S0> {
type MAX = Cons<B0, S0>;
type MIN = Bit0;
type BMAX = BL;
type BMIN = BR;
}
impl<BL, BR, BC, B0: Bit, S0: Positive> Compare<Bit1, BL, BR, BC> for Cons<B0, S0> {
type MAX = Cons<B0, S0>;
type MIN = Bit1;
type BMAX = BL;
type BMIN = BR;
}
impl<BL, BR, BC, B0: Bit, S0: Positive> Compare<Cons<B0, S0>, BL, BR, BC> for Bit0 {
type MAX = Cons<B0, S0>;
type MIN = Bit0;
type BMAX = BR;
type BMIN = BL;
}
impl<BL, BR, BC, B0: Bit, S0: Positive> Compare<Cons<B0, S0>, BL, BR, BC> for Bit1 {
type MAX = Cons<B0, S0>;
type MIN = Bit1;
type BMAX = BR;
type BMIN = BL;
}
impl<BL, BR, BC, S0: Positive, S1: Positive> Compare<Cons<Bit0, S1>, BL, BR, BC> for Cons<Bit0, S0>
where
S0: Compare<S1, BL, BR, BC>,
<S0 as Compare<S1, BL, BR, BC>>::MAX: Positive,
<S0 as Compare<S1, BL, BR, BC>>::MIN: Positive,
{
type MAX = Cons<Bit0, <S0 as Compare<S1, BL, BR, BC>>::MAX>;
type MIN = Cons<Bit0, <S0 as Compare<S1, BL, BR, BC>>::MIN>;
type BMAX = <S0 as Compare<S1, BL, BR, BC>>::BMAX;
type BMIN = <S0 as Compare<S1, BL, BR, BC>>::BMIN;
}
impl<BL, BR, BC, S0: Positive, S1: Positive> Compare<Cons<Bit1, S1>, BL, BR, BC> for Cons<Bit1, S0>
where
S0: Compare<S1, BL, BR, BC>,
<S0 as Compare<S1, BL, BR, BC>>::MAX: Positive,
<S0 as Compare<S1, BL, BR, BC>>::MIN: Positive,
{
type MAX = Cons<Bit1, <S0 as Compare<S1, BL, BR, BC>>::MAX>;
type MIN = Cons<Bit1, <S0 as Compare<S1, BL, BR, BC>>::MIN>;
type BMAX = <S0 as Compare<S1, BL, BR, BC>>::BMAX;
type BMIN = <S0 as Compare<S1, BL, BR, BC>>::BMIN;
}
impl<BL, BR, BC, S0: Positive, S1: Positive> Compare<Cons<Bit1, S1>, BL, BR, BC> for Cons<Bit0, S0>
where
S0: Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit0>>
+ Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit1>>,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit0>>>::BMAX:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit0>>>::BMIN:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit0>>>::MAX:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit0>>>::MIN:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit1>>>::BMAX:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit1>>>::BMIN:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit1>>>::MAX:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit0>, TagBitSet<BR, Bit1>, TagBitSet<BC, Bit1>>>::MIN:
Positive,
{
type MAX =
Cons<
<<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit1>,
>>::BMAX as TagBitSetImpl>::Bit,
<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit1>,
>>::MAX,
>;
type MIN =
Cons<
<<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit0>,
>>::BMIN as TagBitSetImpl>::Bit,
<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit0>,
>>::MIN,
>;
type BMAX = <<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit1>,
>>::BMAX as TagBitSetImpl>::Tag;
type BMIN = <<S0 as Compare<
S1,
TagBitSet<BL, Bit0>,
TagBitSet<BR, Bit1>,
TagBitSet<BC, Bit0>,
>>::BMIN as TagBitSetImpl>::Tag;
}
impl<BL, BR, BC, S0: Positive, S1: Positive> Compare<Cons<Bit0, S1>, BL, BR, BC> for Cons<Bit1, S0>
where
S0: Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit0>>
+ Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit1>>,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit0>>>::BMAX:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit0>>>::BMIN:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit0>>>::MAX:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit0>>>::MIN:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit1>>>::BMAX:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit1>>>::BMIN:
TagBitSetImpl,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit1>>>::MAX:
Positive,
<S0 as Compare<S1, TagBitSet<BL, Bit1>, TagBitSet<BR, Bit0>, TagBitSet<BC, Bit1>>>::MIN:
Positive,
{
type MAX =
Cons<
<<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit1>,
>>::BMAX as TagBitSetImpl>::Bit,
<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit1>,
>>::MAX,
>;
type MIN =
Cons<
<<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit0>,
>>::BMIN as TagBitSetImpl>::Bit,
<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit0>,
>>::MIN,
>;
type BMAX = <<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit1>,
>>::BMAX as TagBitSetImpl>::Tag;
type BMIN = <<S0 as Compare<
S1,
TagBitSet<BL, Bit1>,
TagBitSet<BR, Bit0>,
TagBitSet<BC, Bit0>,
>>::BMIN as TagBitSetImpl>::Tag;
}
pub fn max<V0, V1>(_: &V0, _: &V1) -> <V0 as Compare<V1>>::MAX
where
V0: Compare<V1>,
{
Default::default()
}
pub fn min<V0, V1>(_: &V0, _: &V1) -> <V0 as Compare<V1>>::MIN
where
V0: Compare<V1>,
{
Default::default()
}
#[doc(hidden)]
pub struct TagBitSet<Tag, Bit>(core::marker::PhantomData<(Tag, Bit)>);
#[doc(hidden)]
pub trait TagBitSetImpl {
type Tag;
type Bit: Bit;
}
impl<L, R: Bit> TagBitSetImpl for TagBitSet<L, R> {
type Tag = L;
type Bit = R;
}
#[cfg(test)]
mod test {
use super::*;
use crate::test::if_impl_trait;
use crate::{from_num, FromNum};
fn check_equal<T, U: Equal<T>>() {}
fn check_not_equal<T, U: NotEqual<T>>() {}
fn check_greater_eq<T, U: GreaterOrEqual<T>>() {}
fn check_less_eq<T, U: LessOrEqual<T>>() {}
macro_rules! test_with_number {
(@run eq $m:expr, $n: expr) => {
check_equal::<FromNum<{$m}>, FromNum<{$n}>>();
check_greater_eq::<FromNum<{$n}>, FromNum<{$m}>>();
check_less_eq::<FromNum<{$m}>, FromNum<{$n}>>();
assert!(!if_impl_trait!(FromNum<{$m}>: NotEqual<FromNum<{$n}>>));
assert!(from_num::<{$m}>() == from_num::<{$n}>());
assert!(!(from_num::<{$m}>() > from_num::<{$n}>()));
assert!(!(from_num::<{$m}>() < from_num::<{$n}>()));
assert!(from_num::<{$m}>() >= from_num::<{$n}>());
assert!(from_num::<{$m}>() <= from_num::<{$n}>());
let _: FromNum<{$m}> = max(&from_num::<{$m}>(), &from_num::<{$m}>());
let _: FromNum<{$m}> = min(&from_num::<{$m}>(), &from_num::<{$m}>());
};
(@run neq $m:expr, $n: expr) => { check_not_equal::<FromNum<{$m}>, FromNum<{$n}>>();
check_greater_eq::<FromNum<{$n}>, FromNum<{$m}>>();
check_less_eq::<FromNum<{$m}>, FromNum<{$n}>>();
assert!(!if_impl_trait!(FromNum<{$m}>: Equal<FromNum<{$n}>>));
assert!(!if_impl_trait!(FromNum<{$n}>: GreaterOrEqual<FromNum<{$m}>>));
assert!(!if_impl_trait!(FromNum<{$m}>: LessOrEqual<FromNum<{$n}>>));
assert!(from_num::<{$m}>() != from_num::<{$n}>());
assert!(from_num::<{$m}>() > from_num::<{$n}>());
assert!(!(from_num::<{$m}>() <= from_num::<{$n}>()));
let _: FromNum<{$m}> = max(&from_num::<{$m}>(), &from_num::<{$n}>());
let _: FromNum<{$m}> = max(&from_num::<{$n}>(), &from_num::<{$m}>());
let _: FromNum<{$n}> = min(&from_num::<{$n}>(), &from_num::<{$m}>());
let _: FromNum<{$n}> = min(&from_num::<{$n}>(), &from_num::<{$m}>());
};
(@ $lbl:ident [$($ys:expr),*] [$($zs:expr),*]) => {
test_with_number!(@run $lbl 0usize $(+$ys)*, 0usize $(+$zs)*);
};
(@ $lbl:ident [$($ys:expr),*] [$($zs:expr),*] $x:expr $(,$xs:expr)*) => {
test_with_number!(@ $lbl [$($ys),*][$($zs),*]$($xs),*);
test_with_number!(@ neq [$($ys,)*$x][$($zs),*]$($xs),*);
test_with_number!(@ $lbl [$($ys,)*$x][$($zs,)*$x]$($xs),*);
};
($($xs:expr),*) => {
test_with_number!(@ eq [] [] $($xs),*);
};
}
#[test]
fn test() {
test_with_number!(1, 2, 4, 8, 16);
}
}