dynamic_provider/
tag.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
127
128
129
130
131
use core::{any::TypeId, convert::Infallible, marker::PhantomData};

use crate::{type_fn::TypeFn, LifetimeHkt, Lt};

/// A unique identifier for a specific [`ResourceTag`]-implementing type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TagId(TypeId);

impl TagId {
    /// Returns the Tag ID of type `Tag`.
    pub fn of<Tag: ResourceTag>() -> Self {
        Tag::_tag_id(PreventOverridingTagId)
    }
}

/// This type prevents custom [`ResourceTag`] impls from overriding [`ResourceTag::_tag_id()`] because it's not accessible by
/// name outside of the crate.
pub struct PreventOverridingTagId;

/// A marker type used as a key for requesting values from [`Provide`][crate::Provide].
///
/// ## Note
///
/// Types implementing this trait are generally meant to be used in generic parameters but not instantiated as values.
pub trait ResourceTag: 'static {
    /// A [`TypeFn`] specifying the argument type of this tag.
    /// The argument contains any information needed to provide this resource.
    type Arg: TypeFn;
    /// A [`TypeFn`] specifying the resolved type of this tag.
    type Out: TypeFn;

    #[doc(hidden)]
    fn _tag_id(_: PreventOverridingTagId) -> TagId {
        TagId(TypeId::of::<Self>())
    }
}

/// A [`ResourceTag`] that is defined over the given lifetimes.
///
/// This should not be implemented directly; it will be automatically implemented.
pub trait TagFor<L: Lt>:
    ResourceTag<Arg: TypeFn<Output<L> = Self::ArgValue>, Out: TypeFn<Output<L> = Self::Value>>
{
    /// The argument type.
    type ArgValue;
    /// The output type.
    type Value;
}

impl<Tag, L, ArgValue, Value> TagFor<L> for Tag
where
    Tag: ResourceTag<Arg: TypeFn<Output<L> = ArgValue>, Out: TypeFn<Output<L> = Value>>,
    L: Lt,
{
    type ArgValue = ArgValue;
    type Value = Value;
}

impl ResourceTag for () {
    type Arg = ();
    type Out = ();
}

/// A [`TypeFn`] that corresponds to `T` for all lifetime arguments.
/// Can be used as a [`ResourceTag`] when `T` has a fixed size and contains no borrowed data
/// (i.e. `T: Sized + 'static`).
pub struct Value<T: ?Sized>(Infallible, PhantomData<T>);

impl<T: ?Sized> TypeFn for Value<T> {
    type Output<L: Lt> = T;
}

impl<T: ?Sized + 'static> ResourceTag for Value<T> {
    type Arg = ();
    type Out = crate::TypeFn![T];
}

/// A [`ResourceTag`] that corresponds to a shared reference to the output value of `Tag`.
/// Can also be used as an operator on [`TypeFn`] implementations.
///
/// For example: <code>Ref<[Value<T\>][Value]></code> implements the following for all `'x, T: 'static`:
///
/// ```ignore
/// TypeFn<Output<Lt!['x]> = &'x T> + ResourceTag + TagFor<Lt!['x], Value = &'x T>
/// ```
pub struct Ref<Tag>(Tag);

impl<F> TypeFn for Ref<F>
where
    F: TypeFn,
{
    type Output<L: Lt> = L::Actual<LifetimeHkt![for<'y> &'y F::Output<L>]>;
}

impl<Tag: ResourceTag> ResourceTag for Ref<Tag> {
    type Arg = Tag::Arg;
    type Out = Ref<Tag::Out>;
}

/// A [`ResourceTag`] that corresponds to a unique reference to the output value of `Tag`.
/// Can also be used as an operator on [`TypeFn`] implementations.
///
/// For example: <code>Mut<[Value<T\>][Value]></code> implements the following for all `'x, T: 'static`:
///
/// ```ignore
/// TypeFn<Output<Lt!['x]> = &'x mut T> + ResourceTag + TagFor<Lt!['x], Value = &'x mut T>
/// ```
pub struct Mut<Tag>(Tag);

impl<F> TypeFn for Mut<F>
where
    F: TypeFn,
{
    type Output<L: Lt> = L::Actual<LifetimeHkt![for<'y> &'y mut F::Output<L>]>;
}

impl<Tag: ResourceTag> ResourceTag for Mut<Tag> {
    type Arg = Tag::Arg;
    type Out = Mut<Tag::Out>;
}

/// A tag that is never meant to be fulfilled but has a valid [`TagId`].
pub(crate) struct MarkerTag<T: ?Sized> {
    _p: PhantomData<T>,
    _i: Infallible,
}

impl<T: ?Sized + 'static> ResourceTag for MarkerTag<T> {
    type Arg = ();
    type Out = Value<(Infallible, T)>;
}