use core::{any::TypeId, convert::Infallible, marker::PhantomData};
use crate::{type_fn::TypeFn, LifetimeHkt, Lt};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TagId(TypeId);
impl TagId {
pub fn of<Tag: ResourceTag>() -> Self {
Tag::_tag_id(PreventOverridingTagId)
}
}
pub struct PreventOverridingTagId;
pub trait ResourceTag: 'static {
type Arg: TypeFn;
type Out: TypeFn;
#[doc(hidden)]
fn _tag_id(_: PreventOverridingTagId) -> TagId {
TagId(TypeId::of::<Self>())
}
}
pub trait TagFor<L: Lt>:
ResourceTag<Arg: TypeFn<Output<L> = Self::ArgValue>, Out: TypeFn<Output<L> = Self::Value>>
{
type ArgValue;
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 = ();
}
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];
}
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>;
}
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>;
}
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)>;
}