dynamic_provider/
lt.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use core::{convert::Infallible, marker::PhantomData};

use crate::TypeFn;

mod sealed {
    pub trait LifetimeHkt {}
    pub trait Lt {}
}

#[doc(hidden)]
pub trait _LifetimeHktOf<'lt>: sealed::LifetimeHkt {
    type T: ?Sized;
}

/// Represents a type parameterized by a single lifetime.
/// The [`LifetimeHkt!`][macro@crate::LifetimeHkt] macro is used to get an implementation of this trait.
///
/// Implements [`TypeFn`][trait@crate::TypeFn] when `Actual<'x>: TypeFn`.
///
/// For example, the following type:
///
/// ```
/// use dynamic_provider::{LifetimeHkt, Value};
///
/// type MyTypeFn<T, U, V> = LifetimeHkt![
///     for<'x> LifetimeHkt![
///         for<'y> LifetimeHkt![
///             for<'z> Value<(&'x T, &'y U, &'z V)>
///         ]
///     ]
/// ];
/// ```
///
/// is equivalent to: `TypeFn![for<'x, 'y, 'z> (&'x T, &'y U, &'z V)]`.
pub trait LifetimeHkt {
    /// The described type, given lifetime parameter `'x`.
    type Actual<'x>: ?Sized;
}

pub type Actual<'lt, H> = <H as LifetimeHkt>::Actual<'lt>;

impl<H> LifetimeHkt for HktWrapper<H>
where
    H: ?Sized + for<'x> _LifetimeHktOf<'x>,
{
    type Actual<'x> = <H as _LifetimeHktOf<'x>>::T;
}

#[doc(hidden)]
pub struct Invariant<T: ?Sized>(PhantomData<fn(PhantomData<T>) -> PhantomData<T>>);
#[doc(hidden)]
pub struct Lifetime<'lt>(Invariant<&'lt ()>);

#[doc(hidden)]
pub struct HktWrapper<L: ?Sized>(Infallible, Invariant<L>);

pub type LtList<'x, L = ()> = (Lifetime<'x>, L);

/// Represents a list of zero or more lifetime variables
pub trait Lt: sealed::Lt {
    type Next: Lt;
    type NextExtending: Lt;
    type Extend<'a>: Lt;
    type Actual<H: LifetimeHkt>: ?Sized;
    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>>: TypeFn;
}

impl sealed::Lt for () {}
impl<L> sealed::Lt for LtList<'_, L> where L: sealed::Lt {}

impl Lt for () {
    type Next = ();
    type NextExtending = LtList<'static, Self>;
    type Extend<'a> = LtList<'a, Self>;
    type Actual<H: LifetimeHkt> = H::Actual<'static>;
    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>> = Self::Actual<F>;
}

impl<'lt, L> Lt for LtList<'lt, L>
where
    L: Lt,
{
    type Next = L;
    type NextExtending = L::Extend<'lt>;
    type Extend<'a> = Self;
    type Actual<H: LifetimeHkt> = H::Actual<'lt>;
    type NextTypeFn<F: for<'x> LifetimeHkt<Actual<'x>: TypeFn>> = Self::Actual<F>;
}

impl<T: ?Sized + sealed::LifetimeHkt> sealed::LifetimeHkt for HktWrapper<T> {}

/// Evaluates to an [`Lt`] implementation with the given list of lifetime specifiers.
///
/// ## Usage
///
/// ```ignore
/// Lt!['a, 'b, 'c]
/// ```
///
/// Another lifetime list can be concatenated using `..`:
///
/// ```ignore
/// Lt!['a, 'b, 'c, ..L]
/// ```
#[macro_export]
macro_rules! Lt {
    () => { () };
    ($lt0:lifetime $(, $($rest:tt)*)?) => {
        $crate::lt::LtList::<$lt0, $crate::Lt![$($($rest)*)?]>
    };
    (..$Ty:ty) => { $Ty };
}

/// Evaluates to a [`LifetimeHkt`][trait@LifetimeHkt] implementation.
///
/// ## Usage
///
/// ```ignore
/// LifetimeHkt![for<'x> Cow<'x, str>]
/// ```
#[macro_export]
macro_rules! LifetimeHkt {
    (for <$lt:lifetime> $T:ty) => {
        $crate::lt::HktWrapper::<dyn for<$lt> $crate::lt::_LifetimeHktOf<$lt, T = $T>>
    };
}