dynamic_provider/
lt.rs

1use core::{convert::Infallible, marker::PhantomData};
2
3use crate::TypeFn;
4
5mod sealed {
6    pub trait LifetimeHkt {}
7    pub trait Lt {}
8}
9
10#[doc(hidden)]
11pub trait _LifetimeHktOf<'lt>: sealed::LifetimeHkt {
12    type T: ?Sized;
13}
14
15/// Represents a type parameterized by a single lifetime.
16/// The [`LifetimeHkt!`][macro@crate::LifetimeHkt] macro is used to get an implementation of this trait.
17///
18/// Implements [`TypeFn`][trait@crate::TypeFn] when `Actual<'x>: TypeFn`.
19///
20/// For example, the following type:
21///
22/// ```
23/// use dynamic_provider::{LifetimeHkt, Value};
24///
25/// type MyTypeFn<T, U, V> = LifetimeHkt![
26///     for<'x> LifetimeHkt![
27///         for<'y> LifetimeHkt![
28///             for<'z> Value<(&'x T, &'y U, &'z V)>
29///         ]
30///     ]
31/// ];
32/// ```
33///
34/// is equivalent to: `TypeFn![for<'x, 'y, 'z> (&'x T, &'y U, &'z V)]`.
35pub trait LifetimeHkt {
36    /// The described type, given lifetime parameter `'x`.
37    type Actual<'x>: ?Sized;
38}
39
40pub type Actual<'lt, H> = <H as LifetimeHkt>::Actual<'lt>;
41
42impl<H> LifetimeHkt for HktWrapper<H>
43where
44    H: ?Sized + for<'x> _LifetimeHktOf<'x>,
45{
46    type Actual<'x> = <H as _LifetimeHktOf<'x>>::T;
47}
48
49#[doc(hidden)]
50pub struct Invariant<T: ?Sized>(PhantomData<fn(PhantomData<T>) -> PhantomData<T>>);
51#[doc(hidden)]
52pub struct Lifetime<'lt>(Invariant<&'lt ()>);
53
54#[doc(hidden)]
55pub struct HktWrapper<L: ?Sized>(Infallible, Invariant<L>);
56
57pub type LtList<'x, L = ()> = (Lifetime<'x>, L);
58
59/// Represents a list of zero or more lifetime variables
60pub trait Lt: sealed::Lt {
61    type Next: Lt;
62    type NextExtending: Lt;
63    type Extend<'a>: Lt;
64    type Actual<H: LifetimeHkt>: ?Sized;
65    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>>: TypeFn;
66}
67
68impl sealed::Lt for () {}
69impl<L> sealed::Lt for LtList<'_, L> where L: sealed::Lt {}
70
71impl Lt for () {
72    type Next = ();
73    type NextExtending = LtList<'static, Self>;
74    type Extend<'a> = LtList<'a, Self>;
75    type Actual<H: LifetimeHkt> = H::Actual<'static>;
76    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>> = Self::Actual<F>;
77}
78
79impl<'lt, L> Lt for LtList<'lt, L>
80where
81    L: Lt,
82{
83    type Next = L;
84    type NextExtending = L::Extend<'lt>;
85    type Extend<'a> = Self;
86    type Actual<H: LifetimeHkt> = H::Actual<'lt>;
87    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>> = Self::Actual<F>;
88}
89
90impl<T: ?Sized + sealed::LifetimeHkt> sealed::LifetimeHkt for HktWrapper<T> {}
91
92/// Evaluates to an [`Lt`] implementation with the given list of lifetime specifiers.
93///
94/// ## Usage
95///
96/// ```ignore
97/// Lt!['a, 'b, 'c]
98/// ```
99///
100/// Another lifetime list can be concatenated using `..`:
101///
102/// ```ignore
103/// Lt!['a, 'b, 'c, ..L]
104/// ```
105#[macro_export]
106macro_rules! Lt {
107    () => { () };
108    ($lt0:lifetime $(, $($rest:tt)*)?) => {
109        $crate::lt::LtList::<$lt0, $crate::Lt![$($($rest)*)?]>
110    };
111    (..$Ty:ty) => { $Ty };
112}
113
114/// Evaluates to a [`LifetimeHkt`][trait@LifetimeHkt] implementation.
115///
116/// ## Usage
117///
118/// ```ignore
119/// LifetimeHkt![for<'x> Cow<'x, str>]
120/// ```
121#[macro_export]
122macro_rules! LifetimeHkt {
123    (for <$lt:lifetime> $T:ty) => {
124        $crate::lt::HktWrapper::<dyn for<$lt> $crate::lt::_LifetimeHktOf<$lt, T = $T>>
125    };
126}