use core::marker::PhantomData;
use super::nibble::Nibble;
pub trait HashStream: 'static {
type Head: Nibble;
type Tail: HashStream;
}
pub trait GetTail<D> {
type Out: HashStream;
}
impl<H: HashStream> GetTail<Z> for H {
type Out = Self;
}
impl<H: HashStream, D> GetTail<S<D>> for H
where
H::Tail: GetTail<D>,
{
type Out = <H::Tail as GetTail<D>>::Out;
}
pub struct ConstStream<N>(PhantomData<N>);
impl<N: Nibble + 'static> HashStream for ConstStream<N> {
type Head = N;
type Tail = ConstStream<N>;
}
pub struct AltStream<A, B>(PhantomData<(A, B)>);
impl<A: Nibble + 'static, B: Nibble + 'static> HashStream for AltStream<A, B> {
type Head = A;
type Tail = AltStream<B, A>;
}
pub struct Cons<H, T>(PhantomData<(H, T)>);
impl<H: Nibble + 'static, T: HashStream> HashStream for Cons<H, T> {
type Head = H;
type Tail = T;
}
pub trait Peano {}
pub struct Z;
impl Peano for Z {}
pub struct S<N>(PhantomData<N>);
impl<N: Peano> Peano for S<N> {}
macros::peano!(64);
pub type DefaultMaxDepth = D16;
use super::bool::{Bool, Present, Absent};
pub trait StreamEq<Other: HashStream, Limit> {
type Out: Bool;
}
impl<A: HashStream, B: HashStream> StreamEq<B, Z> for A {
type Out = Present;
}
impl<A, B, L> StreamEq<B, S<L>> for A
where
A: HashStream,
B: HashStream,
A::Head: super::nibble::NibbleEq<B::Head>,
<A::Head as super::nibble::NibbleEq<B::Head>>::Out: StreamEqDispatch<A::Tail, B::Tail, L>,
{
type Out = <<A::Head as super::nibble::NibbleEq<B::Head>>::Out as StreamEqDispatch<A::Tail, B::Tail, L>>::Out;
}
pub trait StreamEqDispatch<TailA, TailB, Limit> {
type Out: Bool;
}
impl<TailA, TailB, L> StreamEqDispatch<TailA, TailB, L> for Absent {
type Out = Absent;
}
impl<TailA, TailB, L> StreamEqDispatch<TailA, TailB, L> for Present
where
TailA: HashStream + StreamEq<TailB, L>,
TailB: HashStream,
{
type Out = <TailA as StreamEq<TailB, L>>::Out;
}
use super::nibble::{X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF};
pub trait SelectNibble<const N: u8> {
type Out: Nibble;
}
macro_rules! impl_select_nibble {
($($val:literal => $nib:ident),* $(,)?) => {
$(
impl SelectNibble<$val> for () {
type Out = $nib;
}
)*
};
}
impl_select_nibble!(
0 => X0, 1 => X1, 2 => X2, 3 => X3,
4 => X4, 5 => X5, 6 => X6, 7 => X7,
8 => X8, 9 => X9, 10 => XA, 11 => XB,
12 => XC, 13 => XD, 14 => XE, 15 => XF,
);
pub struct HashStream16<
const N0: u8, const N1: u8, const N2: u8, const N3: u8,
const N4: u8, const N5: u8, const N6: u8, const N7: u8,
const N8: u8, const N9: u8, const N10: u8, const N11: u8,
const N12: u8, const N13: u8, const N14: u8, const N15: u8,
>(PhantomData<()>);
impl<
const N0: u8, const N1: u8, const N2: u8, const N3: u8,
const N4: u8, const N5: u8, const N6: u8, const N7: u8,
const N8: u8, const N9: u8, const N10: u8, const N11: u8,
const N12: u8, const N13: u8, const N14: u8, const N15: u8,
> HashStream for HashStream16<N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11, N12, N13, N14, N15>
where
(): SelectNibble<N0> + SelectNibble<N1> + SelectNibble<N2> + SelectNibble<N3>
+ SelectNibble<N4> + SelectNibble<N5> + SelectNibble<N6> + SelectNibble<N7>
+ SelectNibble<N8> + SelectNibble<N9> + SelectNibble<N10> + SelectNibble<N11>
+ SelectNibble<N12> + SelectNibble<N13> + SelectNibble<N14> + SelectNibble<N15>,
{
type Head = <() as SelectNibble<N0>>::Out;
type Tail = HashStream16<N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11, N12, N13, N14, N15, N0>;
}