mod tag_type_id;
mod tagged;
use core::marker::PhantomData;
pub use tag_type_id::TagTypeId;
use crate::lt_list::{EmptyLt, LifetimesOf, LtListStructure, ReifyLt, Subset};
use crate::{Lt0, Lt1, LtList};
pub trait Tagged {
type Tag: ?Sized + Tag + Tagged<Tag = Self::Tag> + 'static;
}
pub trait Anything<L: LtList = Lt0>: anything_seal::Sealed<L> {
fn self_tag_id(&self) -> TagTypeId<L>;
fn tag_id() -> TagTypeId<L>
where
Self: Sized;
}
pub trait AnythingExt<L: LtList>: Anything<L> {
fn is<T: Reify<L>>(&self) -> bool {
self.self_tag_id()
.is_same(&TagTypeId::<L>::of::<T::Tag, T::Lifetimes>())
}
fn downcast_ref<T: ReifySized<L>>(&self) -> Option<&T::Reified> {
if self.is::<T>() {
Some(unsafe { &*(self as *const _ as *const T::Reified) })
} else {
None
}
}
fn downcast_mut<T: ReifySized<L>>(&mut self) -> Option<&mut T::Reified> {
if self.is::<T>() {
Some(unsafe { &mut *(self as *mut _ as *mut T::Reified) })
} else {
None
}
}
fn downcast_move<T: ReifySized<L>>(self) -> Result<T::Reified, Self>
where
Self: Sized,
{
if self.is::<T>() {
let this = core::mem::MaybeUninit::new(self);
Ok(unsafe { core::mem::transmute_copy(&this) })
} else {
Err(self)
}
}
}
mod anything_seal {
use super::*;
pub trait Sealed<L: LtList> {}
impl<L: LtList, T: ?Sized + Reify<L, Reified = T>> Sealed<L> for T {}
}
impl<L: LtList, T: ?Sized + Reify<L, Reified = T>> Anything<L> for T {
fn self_tag_id(&self) -> TagTypeId<L> {
TagTypeId::of::<T::Tag, T::Lifetimes>()
}
fn tag_id() -> TagTypeId<L>
where
Self: Sized,
{
TagTypeId::of::<T::Tag, T::Lifetimes>()
}
}
impl<L: LtList, T: ?Sized + Anything<L>> AnythingExt<L> for T {}
pub trait Tag {
type LifetimesTag: LtListStructure + 'static;
}
pub trait Reify<L: LtList>: reify_seal::Sealed<L> {
type Reified: ?Sized;
type Lifetimes: LtList + Subset<L>;
type Tag: ?Sized
+ Tagged<Tag = Self::Tag>
+ Tag<LifetimesTag = Self::LifetimesTag>
+ WithLt<Self::Lifetimes, Reified = Self::Reified>
+ 'static;
type LifetimesTag: ReifyLt<Self::Lifetimes, Lifetimes = Self::Lifetimes>
+ ReifyLt<L, Lifetimes = Self::Lifetimes>
+ 'static;
}
pub trait ReifySized<L: LtList>: Reify<L, Reified = Self::SizedReified> {
type SizedReified;
}
impl<L: LtList, T: ?Sized + Reify<L>> ReifySized<L> for T
where
T::Reified: Sized,
{
type SizedReified = T::Reified;
}
impl<T, L> Reify<L> for T
where
T: ?Sized + Tagged,
L: LtList,
LifetimesTagOf<T::Tag>: ReifyLt<L>,
LifetimesTagOf<T::Tag>: ReifyLt<
LifetimesOf<LifetimesTagOf<T::Tag>, L>,
Lifetimes = LifetimesOf<LifetimesTagOf<T::Tag>, L>,
>,
T::Tag: WithLt<LifetimesOf<LifetimesTagOf<T::Tag>, L>>,
{
type Reified = ReifiedOf<T::Tag, LifetimesOf<LifetimesTagOf<T::Tag>, L>>;
type Lifetimes = LifetimesOf<LifetimesTagOf<T::Tag>, L>;
type Tag = T::Tag;
type LifetimesTag = LifetimesTagOf<T::Tag>;
}
mod reify_seal {
use super::*;
pub trait Sealed<L: LtList> {}
impl<L, T> Sealed<L> for T
where
T: ?Sized + Tagged,
L: LtList,
LifetimesTagOf<T::Tag>: ReifyLt<L>,
LifetimesTagOf<T::Tag>: ReifyLt<
LifetimesOf<LifetimesTagOf<T::Tag>, L>,
Lifetimes = LifetimesOf<LifetimesTagOf<T::Tag>, L>,
>,
T::Tag: WithLt<LifetimesOf<LifetimesTagOf<T::Tag>, L>>,
{
}
}
pub type TagOf<T> = <T as Tagged>::Tag;
pub type LifetimesTagOf<T> = <T as Tag>::LifetimesTag;
pub type ReifiedOf<T, L> = <T as WithLt<L>>::Reified;
pub trait WithLt<L: LtList>: Tag + Tagged<Tag = Self> + 'static {
type Reified: ?Sized;
}
#[allow(clippy::type_complexity)]
pub struct DynTag<LT, T: ?Sized>(PhantomData<(fn() -> *const T, LT)>);
pub trait TagDef<L: LtList>: 'static {
type T: ?Sized;
}
impl<Def: ?Sized + TagDef<L>, L: LtList, LT: ReifyLt<L, Lifetimes = L> + 'static> WithLt<L>
for DynTag<LT, Def>
{
type Reified = Def::T;
}
impl<Def: ?Sized + 'static, LT: LtListStructure + 'static> Tagged for DynTag<LT, Def> {
type Tag = Self;
}
impl<Def: ?Sized + 'static, LT: LtListStructure + 'static> Tag for DynTag<LT, Def> {
type LifetimesTag = LT;
}
pub type Static<T> = tag_for!(T);
pub struct AddLt<T: ?Sized>(PhantomData<fn() -> *const T>);
impl<T: ?Sized + WithLt<L::Tail>, L: LtList> WithLt<L> for AddLt<T> {
type Reified = T::Reified;
}
impl<T: ?Sized + Tagged> Tagged for AddLt<T> {
type Tag = AddLt<T::Tag>;
}
impl<T: ?Sized + Tag> Tag for AddLt<T> {
type LifetimesTag = EmptyLt<T::LifetimesTag>;
}
pub struct Ref<T: ?Sized>(PhantomData<fn() -> T>);
impl<'r, T: ?Sized + WithLt<L>, L: LtList<Head = Lt1<'r>>> WithLt<L> for Ref<T>
where
T::Reified: 'r,
{
type Reified = &'r T::Reified;
}
impl<T: ?Sized + Tagged> Tagged for Ref<T> {
type Tag = Ref<T::Tag>;
}
impl<T: ?Sized + Tag> Tag for Ref<T> {
type LifetimesTag = T::LifetimesTag;
}
pub struct Mut<T: ?Sized>(PhantomData<fn() -> T>);
impl<'r, T: ?Sized + WithLt<L>, L: LtList<Head = Lt1<'r>>> WithLt<L> for Mut<T>
where
T::Reified: 'r,
{
type Reified = &'r mut T::Reified;
}
impl<T: ?Sized + Tagged> Tagged for Mut<T> {
type Tag = Mut<T::Tag>;
}
impl<T: ?Sized + Tag> Tag for Mut<T> {
type LifetimesTag = T::LifetimesTag;
}
#[macro_export]
macro_rules! tag_for {
(<$l0:lifetime, $l1:lifetime, $l2:lifetime $(,)?> $type:ty) => {
$crate::tag::DynTag<$crate::lt_list::EmptyLt<$crate::lt_list::EmptyLt<$crate::lt_list::EmptyLt<()>>>, dyn for<$l0, $l1, $l2> $crate::tag::TagDef<$crate::lt_list::Lt3<$l0, $l1, $l2>, T = $type>>
};
(<$l0:lifetime, $l1:lifetime $(,)?> $type:ty) => {
$crate::tag::DynTag<$crate::lt_list::EmptyLt<$crate::lt_list::EmptyLt<()>>, dyn for<$l0, $l1> $crate::tag::TagDef<$crate::lt_list::Lt2<$l0, $l1>, T = $type>>
};
(<$l0:lifetime $(,)?> $type:ty) => {
$crate::tag::DynTag<$crate::lt_list::EmptyLt<()>, dyn for<$l0> $crate::tag::TagDef<$crate::lt_list::Lt1<$l0>, T = $type>>
};
($type:ty) => {
$crate::tag::DynTag<(), dyn $crate::tag::TagDef<$crate::lt_list::Lt0, T = $type>>
};
}
use tag_for;
#[macro_export]
macro_rules! impl_tagged {
(
$vis:vis struct $name:ident< $($tail:tt)*
) => {
$crate::impl_tagged! {
@scan_generic
{
$vis struct $name
}
()
()
()
()
()
{$($tail)*}
}
};
(
@scan_generic
{$($struct:tt)*}
($($generics:tt)*)
($($reify_generics:tt)*)
($($lt_generics:tt)*)
($($tag_generics:tt)*)
($($const_generics:tt)*)
{$(,)? $generic:ident $(,)? $($tail:tt)*}
) => {
$crate::impl_tagged! {
@scan_generic
{$($struct)*}
($($generics)* $generic,)
($($reify_generics)* $generic::Reified,)
($($lt_generics)*)
($($tag_generics)* $generic,)
($($const_generics)*)
{$($tail)*}
}
};
(
@scan_generic
{$($struct:tt)*}
($($generics:tt)*)
($($reify_generics:tt)*)
($($lt_generics:tt)*)
($($tag_generics:tt)*)
($($const_generics:tt)*)
{$(,)? $lt:lifetime $($tail:tt)*}
) => {
$crate::impl_tagged! {
@scan_generic
{$($struct)*}
($($generics)* $lt,)
($($reify_generics)* $lt,)
($($lt_generics)* $lt,)
($($tag_generics)*)
($($const_generics)*)
{$($tail)*}
}
};
(
@scan_generic
{
$vis:vis struct $name:ident
}
($($generics:tt)*)
($($reify_generics:tt)*)
($($lt_generic:lifetime,)*)
($($tag_generic:ident,)*)
($($const_generics:tt)*)
{$(,)? > $(where $($where:tt)*)?}
) => {
const _: () = {
$vis struct Tag<$($tag_generic: ?Sized)*>(::core::marker::PhantomData<fn() -> ($(*const $tag_generic,)*)>);
impl<$($generics)*> Tagged for $name<$($generics)*>
where
$($tag_generic: Tagged,)*
{
type Tag = Tag<$($tag_generic::Tag)*>;
}
impl<$($lt_generic,)* $($tag_generic,)* L: LtList> WithLt<$crate::impl_tagged!(@lifetime $($lt_generic,)* L)> for Tag<$($tag_generic,)*>
where
$($tag_generic: ?Sized + WithLt<L>,)*
$($tag_generic::Reified: Sized,)*
$($($where)*)?
{
type Reified = $name<$($reify_generics)*>;
}
impl<$($tag_generic: ?Sized + Tagged,)*> Tagged for Tag<$($tag_generic,)*> {
type Tag = Tag<$($tag_generic::Tag)*>;
}
impl<$($tag_generic: ?Sized + supply::tag::Tag,)*> supply::tag::Tag for Tag<$($tag_generic,)*> {
type LifetimesTag = $crate::impl_tagged!(@lifetime_tag $($lt_generic,)* <($($tag_generic::LifetimesTag,)*) as supply::lt_list::MergeTuple>::LtStructure);
}
};
};
(
@lifetime $l0:lifetime, $L:ty
) => {
$crate::lt_list::Lt1<$l0, $L>
};
(
@lifetime_tag $l0:lifetime, $L:ty
) => {
$crate::lt_list::EmptyLt<$L>
};
(
@lifetime $L:ty
) => {
$L
};
(
@lifetime_tag $L:ty
) => {
$L
};
}