use crate::engine::Eval;
use ::typenum as tn;
pub trait Pass: Eval<Result=tn::True> {}
impl<T> Pass for T where T:Eval<Result=tn::True> {}
pub trait Fail: Eval<Result=tn::False> {}
impl<T> Fail for T where T:Eval<Result=tn::False> {}
pub trait List: internal::List {
type Head;
type Tail: internal::List;
type IsEOL;
const LEN: usize;
fn split(self)->(<Self as List>::Head, <Self as List>::Tail);
fn head(&self)->&Self::Head;
fn tail(&self)->&Self::Tail;
fn into_iter_as<X>(self)->Self::ListIter where Self:ListOf<X> {
self.list_of_iter()
}
}
pub trait ListOf<X>: List + Sized {
type ListIter: Iterator<Item=X>;
fn list_of_iter(self)->Self::ListIter;
}
impl<X> ListOf<X> for crate::HNil {
type ListIter = std::iter::Empty<X>;
fn list_of_iter(self)->Self::ListIter {
std::iter::empty()
}
}
impl<H,T,X> ListOf<X> for crate::HCons<H,T>
where T: ListOf<X>, H:Into<X> {
type ListIter = std::iter::Chain<std::iter::Once<X>, T::ListIter>;
fn list_of_iter(self)->Self::ListIter {
std::iter::once(self.head.into()).chain(self.tail.list_of_iter())
}
}
pub struct RefIter<'a,X:?Sized>(&'a dyn ListOfRefs<X>);
impl<'a,X:?Sized> Iterator for RefIter<'a,X> {
type Item = &'a X;
fn next(&mut self)->Option<&'a X> {
let result = self.0.head_ref();
self.0 = self.0.tail_ref();
result
}
}
pub trait ListOfRefs<X:?Sized> {
fn iter(&self)->RefIter<'_,X> where Self:Sized { RefIter(self) }
fn head_ref(&self)->Option<&X>;
fn tail_ref(&self)->&dyn ListOfRefs<X>;
}
impl<X:?Sized> ListOfRefs<X> for crate::HNil {
fn head_ref(&self)->Option<&X> { None }
fn tail_ref(&self)->&dyn ListOfRefs<X> { self }
}
impl<H,T,X:?Sized> ListOfRefs<X> for crate::HCons<H,T>
where T: ListOfRefs<X>, H:AsRef<X> {
fn head_ref(&self)->Option<&X> { Some(self.head.as_ref()) }
fn tail_ref(&self)->&dyn ListOfRefs<X> { &self.tail }
}
impl<T> List for T where T:internal::List {
type Head = <Self as internal::List>::IHead;
type Tail = <Self as internal::List>::ITail;
type IsEOL = <Self as internal::List>::IIsEOL;
const LEN:usize = <Self as internal::List>::ILEN;
#[inline(always)]
fn split(self)->(<Self as List>::Head, <Self as List>::Tail) { self.i_split() }
#[inline(always)]
fn head(&self)->&Self::Head { self.i_head() }
#[inline(always)]
fn tail(&self)->&Self::Tail { self.i_tail() }
}
mod internal {
pub trait List {
type IHead;
type ITail: List;
type IIsEOL;
const ILEN:usize;
fn i_split(self)->(Self::IHead, Self::ITail);
fn i_head(&self)->&Self::IHead;
fn i_tail(&self)->&Self::ITail;
}
impl List for crate::HNil {
type IHead = Self;
type ITail = Self;
type IIsEOL = ::typenum::True;
const ILEN:usize = 0;
#[inline(always)]
fn i_split(self)->(Self,Self) { (crate::HNil, crate::HNil) }
#[inline(always)]
fn i_head(&self)->&Self::IHead { self }
#[inline(always)]
fn i_tail(&self)->&Self::ITail { self }
}
impl<H,T:List> List for crate::HCons<H,T>
{
type IHead = H;
type ITail = T;
type IIsEOL = ::typenum::False;
const ILEN: usize = 1+T::ILEN;
#[inline(always)]
fn i_split(self)->(H,T) { let crate::HCons { head: h, tail: t} = self; (h,t) }
#[inline(always)]
fn i_head(&self)->&Self::IHead { &self.head }
#[inline(always)]
fn i_tail(&self)->&Self::ITail { &self.tail }
}
}