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)>;
}