dynamic_provider/
tag.rs

1use core::{any::TypeId, convert::Infallible, marker::PhantomData};
2
3use crate::{type_fn::TypeFn, LifetimeHkt, Lt};
4
5/// A unique identifier for a specific [`ResourceTag`]-implementing type.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct TagId(TypeId);
8
9impl TagId {
10    /// Returns the Tag ID of type `Tag`.
11    pub fn of<Tag: ResourceTag>() -> Self {
12        Tag::_tag_id(PreventOverridingTagId)
13    }
14}
15
16/// This type prevents custom [`ResourceTag`] impls from overriding [`ResourceTag::_tag_id()`] because it's not accessible by
17/// name outside of the crate.
18pub struct PreventOverridingTagId;
19
20/// A marker type used as a key for requesting values from [`Provide`][crate::Provide].
21///
22/// ## Note
23///
24/// Types implementing this trait are generally meant to be used in generic parameters but not instantiated as values.
25pub trait ResourceTag: 'static {
26    /// A [`TypeFn`] specifying the argument type of this tag.
27    /// The argument contains any information needed to provide this resource.
28    type Arg: TypeFn;
29    /// A [`TypeFn`] specifying the resolved type of this tag.
30    type Out: TypeFn;
31
32    #[doc(hidden)]
33    fn _tag_id(_: PreventOverridingTagId) -> TagId {
34        TagId(TypeId::of::<Self>())
35    }
36}
37
38/// A [`ResourceTag`] that is defined over the given lifetimes.
39///
40/// This should not be implemented directly; it will be automatically implemented.
41pub trait TagFor<L: Lt>:
42    ResourceTag<Arg: TypeFn<Output<L> = Self::ArgValue>, Out: TypeFn<Output<L> = Self::Value>>
43{
44    /// The argument type.
45    type ArgValue;
46    /// The output type.
47    type Value;
48}
49
50impl<Tag, L, ArgValue, Value> TagFor<L> for Tag
51where
52    Tag: ResourceTag<Arg: TypeFn<Output<L> = ArgValue>, Out: TypeFn<Output<L> = Value>>,
53    L: Lt,
54{
55    type ArgValue = ArgValue;
56    type Value = Value;
57}
58
59impl ResourceTag for () {
60    type Arg = ();
61    type Out = ();
62}
63
64/// A [`TypeFn`] that corresponds to `T` for all lifetime arguments.
65/// Can be used as a [`ResourceTag`] when `T` has a fixed size and contains no borrowed data
66/// (i.e. `T: Sized + 'static`).
67pub struct Value<T: ?Sized>(Infallible, PhantomData<T>);
68
69impl<T: ?Sized> TypeFn for Value<T> {
70    type Output<L: Lt> = T;
71}
72
73impl<T: ?Sized + 'static> ResourceTag for Value<T> {
74    type Arg = ();
75    type Out = crate::TypeFn![T];
76}
77
78/// A [`ResourceTag`] that corresponds to a shared reference to the output value of `Tag`.
79/// Can also be used as an operator on [`TypeFn`] implementations.
80///
81/// For example: <code>Ref<[Value<T\>][Value]></code> implements the following for all `'x, T: 'static`:
82///
83/// ```ignore
84/// TypeFn<Output<Lt!['x]> = &'x T> + ResourceTag + TagFor<Lt!['x], Value = &'x T>
85/// ```
86pub struct Ref<Tag>(Tag);
87
88impl<F> TypeFn for Ref<F>
89where
90    F: TypeFn,
91{
92    type Output<L: Lt> = L::Actual<LifetimeHkt![for<'y> &'y F::Output<L>]>;
93}
94
95impl<Tag: ResourceTag> ResourceTag for Ref<Tag> {
96    type Arg = Tag::Arg;
97    type Out = Ref<Tag::Out>;
98}
99
100/// A [`ResourceTag`] that corresponds to a unique reference to the output value of `Tag`.
101/// Can also be used as an operator on [`TypeFn`] implementations.
102///
103/// For example: <code>Mut<[Value<T\>][Value]></code> implements the following for all `'x, T: 'static`:
104///
105/// ```ignore
106/// TypeFn<Output<Lt!['x]> = &'x mut T> + ResourceTag + TagFor<Lt!['x], Value = &'x mut T>
107/// ```
108pub struct Mut<Tag>(Tag);
109
110impl<F> TypeFn for Mut<F>
111where
112    F: TypeFn,
113{
114    type Output<L: Lt> = L::Actual<LifetimeHkt![for<'y> &'y mut F::Output<L>]>;
115}
116
117impl<Tag: ResourceTag> ResourceTag for Mut<Tag> {
118    type Arg = Tag::Arg;
119    type Out = Mut<Tag::Out>;
120}
121
122/// A tag that is never meant to be fulfilled but has a valid [`TagId`].
123pub(crate) struct MarkerTag<T: ?Sized> {
124    _p: PhantomData<T>,
125    _i: Infallible,
126}
127
128impl<T: ?Sized + 'static> ResourceTag for MarkerTag<T> {
129    type Arg = ();
130    type Out = Value<(Infallible, T)>;
131}