use core::marker::PhantomData;
use crate::primitives::{Bool, Present, Absent, BoolAnd};
use crate::primitives::nibble::{Nibble, NibbleEq};
pub struct FEmpty;
pub struct FSingle<A>(PhantomData<A>);
pub struct FDeep<M, P, S, X>(PhantomData<(M, P, S, X)>);
pub struct D1<A>(PhantomData<A>);
pub struct D2<A, B>(PhantomData<(A, B)>);
pub struct D3<A, B, C>(PhantomData<(A, B, C)>);
pub struct D4<A, B, C, D>(PhantomData<(A, B, C, D)>);
pub struct N2<M, A, B>(PhantomData<(M, A, B)>);
pub struct N3<M, A, B, C>(PhantomData<(M, A, B, C)>);
pub struct H0;
#[allow(clippy::type_complexity)]
pub struct HVal<N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, NA, NB, NC, ND, NE, NF>(
PhantomData<(N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, NA, NB, NC, ND, NE, NF)>
);
pub trait Measured {
type Measure;
}
impl Measured for FEmpty {
type Measure = H0;
}
impl<A: Measured> Measured for FSingle<A> {
type Measure = A::Measure;
}
impl<M, P, S, X> Measured for FDeep<M, P, S, X> {
type Measure = M; }
pub trait MeasureEq<Other> {
type Out: Bool;
}
impl MeasureEq<H0> for H0 {
type Out = Present;
}
impl<
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, AA, AB, AC, AD, AE, AF,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF,
> MeasureEq<HVal<B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF>>
for HVal<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, AA, AB, AC, AD, AE, AF>
where
A0: Nibble + NibbleEq<B0>, A1: Nibble + NibbleEq<B1>,
A2: Nibble + NibbleEq<B2>, A3: Nibble + NibbleEq<B3>,
A4: Nibble + NibbleEq<B4>, A5: Nibble + NibbleEq<B5>,
A6: Nibble + NibbleEq<B6>, A7: Nibble + NibbleEq<B7>,
A8: Nibble + NibbleEq<B8>, A9: Nibble + NibbleEq<B9>,
AA: Nibble + NibbleEq<BA>, AB: Nibble + NibbleEq<BB>,
AC: Nibble + NibbleEq<BC>, AD: Nibble + NibbleEq<BD>,
AE: Nibble + NibbleEq<BE>, AF: Nibble + NibbleEq<BF>,
B0: Nibble, B1: Nibble, B2: Nibble, B3: Nibble,
B4: Nibble, B5: Nibble, B6: Nibble, B7: Nibble,
B8: Nibble, B9: Nibble, BA: Nibble, BB: Nibble,
BC: Nibble, BD: Nibble, BE: Nibble, BF: Nibble,
<A0 as NibbleEq<B0>>::Out: BoolAnd<<A1 as NibbleEq<B1>>::Out>,
<<A0 as NibbleEq<B0>>::Out as BoolAnd<<A1 as NibbleEq<B1>>::Out>>::Out: BoolAnd<<A2 as NibbleEq<B2>>::Out>,
{
type Out = <A0 as NibbleEq<B0>>::Out;
}
pub trait FingerEq<Other> {
type Out: Bool;
}
impl FingerEq<FEmpty> for FEmpty {
type Out = Present;
}
impl<A> FingerEq<FSingle<A>> for FEmpty {
type Out = Absent;
}
impl<M, P, S, X> FingerEq<FDeep<M, P, S, X>> for FEmpty {
type Out = Absent;
}
impl<A> FingerEq<FEmpty> for FSingle<A> {
type Out = Absent;
}
impl<M, P, S, X> FingerEq<FEmpty> for FDeep<M, P, S, X> {
type Out = Absent;
}
impl<A, B> FingerEq<FSingle<B>> for FSingle<A>
where
A: super::identity::IdentityEq<B>,
{
type Out = <A as super::identity::IdentityEq<B>>::Out;
}
impl<A, M, P, S, X> FingerEq<FDeep<M, P, S, X>> for FSingle<A> {
type Out = Absent;
}
impl<A, M, P, S, X> FingerEq<FSingle<A>> for FDeep<M, P, S, X> {
type Out = Absent;
}
impl<M1, P1, S1, X1, M2, P2, S2, X2> FingerEq<FDeep<M2, P2, S2, X2>> for FDeep<M1, P1, S1, X1>
where
M1: MeasureEq<M2>,
P1: DigitEq<P2>,
S1: FingerEq<S2>,
X1: DigitEq<X2>,
<M1 as MeasureEq<M2>>::Out: BoolAnd<<P1 as DigitEq<P2>>::Out>,
<<M1 as MeasureEq<M2>>::Out as BoolAnd<<P1 as DigitEq<P2>>::Out>>::Out:
BoolAnd<<S1 as FingerEq<S2>>::Out>,
<<<M1 as MeasureEq<M2>>::Out as BoolAnd<<P1 as DigitEq<P2>>::Out>>::Out as
BoolAnd<<S1 as FingerEq<S2>>::Out>>::Out: BoolAnd<<X1 as DigitEq<X2>>::Out>,
{
type Out = <<<<M1 as MeasureEq<M2>>::Out
as BoolAnd<<P1 as DigitEq<P2>>::Out>>::Out
as BoolAnd<<S1 as FingerEq<S2>>::Out>>::Out
as BoolAnd<<X1 as DigitEq<X2>>::Out>>::Out;
}
pub trait DigitEq<Other> {
type Out: Bool;
}
impl<A, B> DigitEq<D1<B>> for D1<A>
where A: super::identity::IdentityEq<B> {
type Out = <A as super::identity::IdentityEq<B>>::Out;
}
impl<A1, A2, B1, B2> DigitEq<D2<B1, B2>> for D2<A1, A2>
where
A1: super::identity::IdentityEq<B1>,
A2: super::identity::IdentityEq<B2>,
<A1 as super::identity::IdentityEq<B1>>::Out: BoolAnd<<A2 as super::identity::IdentityEq<B2>>::Out>,
{
type Out = <<A1 as super::identity::IdentityEq<B1>>::Out
as BoolAnd<<A2 as super::identity::IdentityEq<B2>>::Out>>::Out;
}
impl<A, B1, B2> DigitEq<D2<B1, B2>> for D1<A> { type Out = Absent; }
impl<A1, A2, B> DigitEq<D1<B>> for D2<A1, A2> { type Out = Absent; }
use super::identity::IdentityEq;
impl IdentityEq<FEmpty> for FEmpty {
type Out = Present;
}
impl<A> IdentityEq<FSingle<A>> for FEmpty {
type Out = Absent;
}
impl<M, P, S, X> IdentityEq<FDeep<M, P, S, X>> for FEmpty {
type Out = Absent;
}
impl<A> IdentityEq<FEmpty> for FSingle<A> {
type Out = Absent;
}
impl<A, B> IdentityEq<FSingle<B>> for FSingle<A>
where
A: IdentityEq<B>,
{
type Out = <A as IdentityEq<B>>::Out;
}
impl<A, M, P, S, X> IdentityEq<FDeep<M, P, S, X>> for FSingle<A> {
type Out = Absent;
}
impl<M, P, S, X> IdentityEq<FEmpty> for FDeep<M, P, S, X> {
type Out = Absent;
}
impl<M, P, S, X, A> IdentityEq<FSingle<A>> for FDeep<M, P, S, X> {
type Out = Absent;
}
impl<M1, P1, S1, X1, M2, P2, S2, X2> IdentityEq<FDeep<M2, P2, S2, X2>> for FDeep<M1, P1, S1, X1>
where
Self: FingerEq<FDeep<M2, P2, S2, X2>>,
{
type Out = <Self as FingerEq<FDeep<M2, P2, S2, X2>>>::Out;
}