use core::marker::PhantomData;
use core::panic::{RefUnwindSafe, UnwindSafe};
pub trait LtList:
Prefix<Self> + Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + lt_list_seal::Sealed
{
type Head: Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe;
type Tail: LtList;
type Tag: FirstN<Self, Lifetimes = Self> + 'static;
}
pub trait LtHoleList: 'static {
type Head;
type Tail: LtHoleList;
}
mod lt_list_seal {
use super::*;
pub trait Sealed {}
impl Sealed for Nil {}
impl<T: LtListElement, Tail: LtList> Sealed for Cons<T, Tail> {}
}
pub trait LtListElement: Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe {}
pub trait LtHoleListElement: Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe {}
#[non_exhaustive]
pub struct Nil;
impl LtList for Nil {
type Head = Inv<'static>;
type Tail = Nil;
type Tag = Nil;
}
impl LtHoleList for Nil {
type Head = Nil;
type Tail = Nil;
}
pub struct Cons<T, Tail = Nil>(PhantomData<fn() -> (T, Tail)>);
impl<T: LtListElement, Tail: LtList> LtList for Cons<T, Tail> {
type Head = T;
type Tail = Tail;
type Tag = Cons<Hole, Tail::Tag>;
}
impl<Tail: LtHoleList> LtHoleList for Cons<Hole, Tail> {
type Head = Hole;
type Tail = Tail;
}
#[non_exhaustive]
pub struct Hole;
pub struct Inv<'lt>(PhantomData<fn(&'lt ()) -> &'lt ()>);
impl<'lt> LtListElement for Inv<'lt> {}
pub trait FirstN<L: LtList>: LtHoleList {
type Lifetimes: LtList<Tag = Self> + Prefix<L>;
}
impl<L: LtList> FirstN<L> for Nil {
type Lifetimes = Nil;
}
impl<Tail: LtHoleList + FirstN<L::Tail>, L: LtList> FirstN<L> for Cons<Hole, Tail>
where
L::Head: LtListElement,
{
type Lifetimes = Cons<L::Head, <Tail as FirstN<L::Tail>>::Lifetimes>;
}
pub trait Prefix<More: lt_list_seal::Sealed>: lt_list_seal::Sealed {}
impl<L: LtList> Prefix<L> for Nil {}
impl<Tail: LtList + Prefix<L::Tail>, L: LtList> Prefix<L> for Cons<L::Head, Tail> where
L::Head: LtListElement
{
}
pub trait Longest {
type Holes: LtHoleList;
}
type L<L1, L2> = <(L1, L2) as Longest>::Holes;
impl Longest for () {
type Holes = Nil;
}
impl<L: LtHoleList> Longest for (L,) {
type Holes = L;
}
impl<L> Longest for (L, Nil)
where
L: LtHoleList,
{
type Holes = L;
}
impl<Tail0, Tail1> Longest for (Cons<Hole, Tail0>, Cons<Hole, Tail1>)
where
Tail0: LtHoleList,
Tail1: LtHoleList,
(Tail0, Tail1): Longest,
{
type Holes = Cons<Hole, <(Tail0, Tail1) as Longest>::Holes>;
}
impl<L0, L1, L2> Longest for (L0, L1, L2)
where
L0: LtHoleList,
L1: LtHoleList,
L2: LtHoleList,
(L0, L1): Longest,
(L<L0, L1>, L2): Longest,
{
type Holes = L<L<L0, L1>, L2>;
}
impl<L0, L1, L2, L3> Longest for (L0, L1, L2, L3)
where
L0: LtHoleList,
L1: LtHoleList,
L2: LtHoleList,
L3: LtHoleList,
(L0, L1): Longest,
(L<L0, L1>, L2): Longest,
(L<L<L0, L1>, L2>, L3): Longest,
{
type Holes = L<L<L<L0, L1>, L2>, L3>;
}
impl<L0, L1, L2, L3, L4> Longest for (L0, L1, L2, L3, L4)
where
L0: LtHoleList,
L1: LtHoleList,
L2: LtHoleList,
L3: LtHoleList,
L4: LtHoleList,
(L0, L1): Longest,
(L<L0, L1>, L2): Longest,
(L<L<L0, L1>, L2>, L3): Longest,
(L<L<L<L0, L1>, L2>, L3>, L4): Longest,
{
type Holes = L<L<L<L<L0, L1>, L2>, L3>, L4>;
}
impl<L0, L1, L2, L3, L4, L5> Longest for (L0, L1, L2, L3, L4, L5)
where
L0: LtHoleList,
L1: LtHoleList,
L2: LtHoleList,
L3: LtHoleList,
L4: LtHoleList,
L5: LtHoleList,
(L0, L1): Longest,
(L<L0, L1>, L2): Longest,
(L<L<L0, L1>, L2>, L3): Longest,
(L<L<L<L0, L1>, L2>, L3>, L4): Longest,
(L<L<L<L<L0, L1>, L2>, L3>, L4>, L5): Longest,
{
type Holes = L<L<L<L<L<L0, L1>, L2>, L3>, L4>, L5>;
}
#[macro_export]
macro_rules! l {
[$l0:lifetime, $l1:lifetime, $l2:lifetime, $tail:ty $(,)?] => {
$crate::lt_list::Lt3<$l0, $l1, $l2, $tail>
};
[$l0:lifetime, $l1:lifetime, $l2:lifetime $(,)?] => {
$crate::lt_list::Lt3<$l0, $l1, $l2>
};
[$l0:lifetime, $l1:lifetime, $tail:ty $(,)?] => {
$crate::lt_list::Lt2<$l0, $l1, $tail>
};
[$l0:lifetime, $l1:lifetime $(,)?] => {
$crate::lt_list::Lt2<$l0, $l1>
};
[$l0:lifetime, $tail:ty $(,)?] => {
$crate::lt_list::Lt1<$l0, $tail>
};
[$l0:lifetime $(,)?] => {
$crate::lt_list::Lt1<$l0>
};
[$($tail:ty)? $(,)?] => {
$crate::lt_list::Lt0$(<$tail>)?
};
}
#[doc(inline)]
pub use l;
#[doc(hidden)]
#[macro_export]
macro_rules! lt_structure {
['_, '_, '_, $tail:ty $(,)?] => {
$crate::lt_list::LtH3<$tail>
};
['_, '_, '_ $(,)?] => {
$crate::lt_list::LtH3
};
['_, '_, $tail:ty $(,)?] => {
$crate::lt_list::LtH2<$tail>
};
['_, '_ $(,)?] => {
$crate::lt_list::LtH2
};
['_, $tail:ty $(,)?] => {
$crate::lt_list::LtH1<$tail>
};
['_ $(,)?] => {
$crate::lt_list::LtH1
};
[$tail:ty $(,)?] => {
$crate::lt_list::LtH0<$tail>
};
[$(,)?] => {
$crate::lt_list::LtH0
};
}
#[doc(inline)]
pub use lt_structure;
pub type Lt0<L = Nil> = L;
pub type Lt1<'l0, L = Nil> = Cons<Inv<'l0>, L>;
pub type Lt2<'l0, 'l1, L = Nil> = Cons<Inv<'l0>, Cons<Inv<'l1>, L>>;
pub type Lt3<'l0, 'l1, 'l2, L = Nil> = Cons<Inv<'l0>, Cons<Inv<'l1>, Cons<Inv<'l2>, L>>>;
pub type Lt4<'l0, 'l1, 'l2, 'l3, L = Nil> =
Cons<Inv<'l0>, Cons<Inv<'l1>, Cons<Inv<'l2>, Cons<Inv<'l3>, L>>>>;
pub type Lt5<'l0, 'l1, 'l2, 'l3, 'l4, L = Nil> =
Cons<Inv<'l0>, Cons<Inv<'l1>, Cons<Inv<'l2>, Cons<Inv<'l3>, Cons<Inv<'l4>, L>>>>>;
pub type Lt6<'l0, 'l1, 'l2, 'l3, 'l4, 'l5, L = Nil> = Cons<
Inv<'l0>,
Cons<Inv<'l1>, Cons<Inv<'l2>, Cons<Inv<'l3>, Cons<Inv<'l4>, Cons<Inv<'l5>, L>>>>>,
>;
pub type LtH0<L = Nil> = L;
pub type LtH1<L = Nil> = Cons<Hole, L>;
pub type LtH2<L = Nil> = Cons<Hole, Cons<Hole, L>>;
pub type LtH3<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, L>>>;
pub type LtH4<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>;
pub type LtH5<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>>;
pub type LtH6<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>>>;