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}