supply 0.2.0

Provider API for arbitrary number of lifetimes.
Documentation
//! List of lifetimes `Lt<'a, Lt<'b, Lt<'c, ...>>>`.
//!
//! This module implements a `cons` list for lifetimes.
//! This allows APIs to work on an arbitrary number of lifetimes.
//!
//! See the [`tag`][crate::tag] module for a usage of these lifetime lists.
//! Most of the time only [`LtList`] is needed as a generic bound along with the
//! `LtN` type aliases.
//!
//! ## Invariants
//!
//! This module provides a few invariants for unsafe code to use.
//!
//! 1. [`LtList`] implementers are invariant over their contained lifetimes.
//!    - This means that unsafe code can use the borrow checker to assert the lifetimes contained
//!      are the exact same.
//! 2. [`LtList::Tag`] is unique per lifetime list minus the lifetimes in the
//!    list.
//!    - This means that it would be unique between `<'a, 'b, 'c>` and `<'a, 'b>` but not unique
//!      between `<'a, 'b>` and `<'b, 'c`>.
//! 3. [`Subset`] implementers always connect the shared lifetimes.
//!    - This means that `<'a, 'b>` being a subset of `<'c, 'd, 'e>` results in `'a == 'c` and
//!      `'b == 'd`.

use core::marker::PhantomData;
use core::panic::{RefUnwindSafe, UnwindSafe};

/// A type level `cons` list of lifetimes.
///
/// All lists are invariant over their lifetimes.
///
/// This trait is sealed and is only implemented for `()` and [`Lt`].
// The Sized here is important to prevent `dyn LtList` which has
// subtyping relations. Unsafe code relies on LtList generics being
// fully invariant.
pub trait LtList:
    Prefix<Self> + Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + lt_list_seal::Sealed
{
    /// A [`Lt`] type with the first lifetime.
    ///
    /// The lifetime is `'static` for zero length lists.
    type Head: Sized + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe;

    /// The rest of the lifetimes.
    type Tail: LtList;

    /// `'static` type that acts as a tag for the lifetime list.
    ///
    /// This is used by [`TagTypeId`](crate::tag::TagTypeId).
    type Tag: FirstN<Self, Lifetimes = Self> + 'static;
}

/// A [`LtList`] without it's lifetimes.
///
/// This allows encoding the length of a [`LtList`] as a `'static` type.
/// See [`ReifyLt`] for adding the lifetimes.
///
/// This trait is sealed and is only implemented by `()` and [`EmptyLt`].
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;
}

/// `cons` of a lifetime `'lt` and a tail.
///
/// This struct is invariant over `'lt`.
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> {}

/// Adds the lifetimes from `L` into the empty list.
///
/// This allows a type tag to also store the lifetime it needs.
/// This need can then be filled in later with real lifetimes using this trait.
// This is already sealed via LtListStructure so it doesn't need it's own.
pub trait FirstN<L: LtList>: LtHoleList {
    /// Some subset of `L` with the same length as `Self`.
    ///
    /// For example, if `L = <'a, 'b, 'c>` and `Self` has length 2, then
    /// `Lifetimes = <'a, 'b>`.
    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>;
}

/// Implemented when `Self` is a subset of another list of lifetimes.
///
/// Being a subset means that the list has less or equal lifetimes than the other list.
/// For example, `<'a, 'b>` is a subset of `<'a, 'b, 'c>` because there is an extra `'c`
/// lifetime. Additionally, all lists are subsets of themselves. However, different lifetimes
/// do not form a subset. For example, `<'a, 'b>` is not a subset of `<'c, 'd, 'e>` where `'a !=
/// 'c` and `'b != 'd`.
///
/// This property is used to allow providing values with less lifetime needs than the
/// provider can provide.
///
/// This trait is sealed and is only implemented by `()` and [`Lt`].
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
{
}

/// Merge two lifetime list structures into one by taking the larger.
///
/// This trait is sealed and is only implemented by `()` and [`EmptyLt`].
pub trait Longest {
    /// The larger of the lifetime list structures.
    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>;
}

/// Create lifetime lists easily.
///
/// This macro accepts a list of lifetimes and generates the corresponding
/// [`LtList`] type.
#[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;

/// `<>`
///
/// `L` is an arbitrary list. No lifetimes is an empty list, so 'L' is the list
/// after combining them.
pub type Lt0<L = Nil> = L;

/// `<'a>`
///
/// `L` is an arbitrary list to place after the given lifetime.
pub type Lt1<'l0, L = Nil> = Cons<Inv<'l0>, L>;

/// `<'a, 'b>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type Lt2<'l0, 'l1, L = Nil> = Cons<Inv<'l0>, Cons<Inv<'l1>, L>>;

/// `<'a, 'b, 'c>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type Lt3<'l0, 'l1, 'l2, L = Nil> = Cons<Inv<'l0>, Cons<Inv<'l1>, Cons<Inv<'l2>, L>>>;

/// `<'a, 'b, 'c, 'd>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type Lt4<'l0, 'l1, 'l2, 'l3, L = Nil> =
    Cons<Inv<'l0>, Cons<Inv<'l1>, Cons<Inv<'l2>, Cons<Inv<'l3>, L>>>>;

/// `<'a, 'b, 'c, 'd, 'e>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
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>>>>>;

/// `<'a, 'b, 'c, 'd, 'e, 'f>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
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>>>>>,
>;

/// `<>`
///
/// `L` is an arbitrary list. No lifetimes is an empty list, so 'L' is the list
/// after combining them.
pub type LtH0<L = Nil> = L;

/// `<'_>`
///
/// `L` is an arbitrary list to place after the given lifetime.
pub type LtH1<L = Nil> = Cons<Hole, L>;

/// `<'_, '_>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type LtH2<L = Nil> = Cons<Hole, Cons<Hole, L>>;

/// `<'_, '_, '_>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type LtH3<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, L>>>;

/// `<'_, '_, '_, '_>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type LtH4<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>;

/// `<'_, '_, '_, '_, '_>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type LtH5<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>>;

/// `<'_, '_, '_, '_, '_, '_>`
///
/// `L` is an arbitrary list to place after the given lifetimes.
pub type LtH6<L = Nil> = Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, Cons<Hole, L>>>>>>;