-rw-r--r--src/any.rs353
-rw-r--r--src/any/static_wrapper.rs60
-rw-r--r--src/lib.rs2
3 files changed, 327 insertions, 88 deletions
diff --git a/src/any.rs b/src/any.rs
index 8296403..94998f8 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -1,63 +1,129 @@
+//! Extended type erasure support.
+//!
+//! The [`core::any`] module, and [`Any`][core::any::Any] in particular,
+//! provide great utilities to perform type erasure. However, there are some
+//! limitations. Namely `Any` requires the type be `'static`. This doesn't
+//! work for [`treaty`][crate] as it needs the `'ctx` lifetime.
+//! Also `Any` doesn't allow type erasing `!Sized` types as this would
+//! result in a "double fat pointer"?!, and those don't exist.
+//!
+//! This module solves both problems. First, [`LtAny`] is a lifetime containing
+//! counterpart to [`Any`][core::any::Any]. [`LtAny`] allows one lifetime which
+//! [`treaty`][crate] uses for the `'ctx` lifetime shared by walkers and visitors.
+//! Second, [`IndirectLtAny`] is able to type erase a pointer like type even
+//! if it's a `!Sized` type. This allows for type erasing borrows of trait objects
+//! like `&dyn Trait`.
+//!
+//! For a type to be compatible with this module it needs to implement [`TypeNameable`]
+//! to give it a unique [`TypeId`][core::any::TypeId]. This can be done manually
+//! without unsafe code. However, its recommended to use the provided [`nameable`]
+//! macro when possible.
+
+pub mod static_wrapper;
+
use core::{
marker::{PhantomData, PhantomPinned},
mem::{ManuallyDrop, MaybeUninit},
};
+#[cfg(all(feature = "alloc", not(feature = "std")))]
+use alloc::boxed::Box;
+
+/// A type with another type acting as its name.
+///
+/// The `'a` lifetime is the lifetime `Self` must outlive.
+/// The `'lt` lifetime is some arbitrary lifetime `Self` can use in it's definition.
+///
+/// The [`nameable`] allows implementing this trait and [`TypeName`] with minimal effort.
+/// For types that are `'static` they can be wrapped by the included wrappers in
+/// the [`static_wrapper`] module.
+///
+/// This trait is circular with [`TypeName`] on [`Self::Name`].
+/// As a result, both must be implemented with matching implementations,
+/// and each type can only be used as the name for one type.
pub trait TypeNameable<'a, 'lt>: 'a {
+ /// The type acting to name `Self`.
+ ///
+ /// This name type is unique to this `Self` type.
type Name: ?Sized + TypeName<'a, 'lt, Nameable = Self>;
}
+/// The pair trait to [`TypeNameable`].
+///
+/// This trait is implemented by types acting as names.
+/// Each name type can only be used to name one type.
+///
+/// This type must be `'static` so it works with [`TypeId`][core::any::TypeId].
pub trait TypeName<'a, 'lt>: 'static {
+ /// The type this type names.
+ ///
+ /// In some sense, this is the lifetime poisoned form of `Self`.
type Nameable: ?Sized + TypeNameable<'a, 'lt, Name = Self>;
}
+/// Implement [`TypeNameable`] and generate a unique name type.
+///
+/// ```
+/// use treaty::any::{nameable, TypeNameable, TypeName};
+///
+/// pub struct MyType<T>(pub T);
+///
+/// nameable! {
+/// pub struct Name['a, 'lt, T];
+/// impl [T::Name] for MyType<T> where { T: TypeNameable<'a, 'lt>, T::Name: Sized }
+/// impl [T] where MyType<T::Nameable> { T: TypeName<'a, 'lt>, T::Nameable: Sized }
+/// }
+/// ```
+///
+/// The generated `Name` struct will not be nameable outside the macro.
+/// Its only purpose is to be a unique type to act as a name.
+/// The first `impl` is for [`TypeNameable`] on the type given between the `for` and `where`.
+/// The first list of generics are what will be passed to the generics of `Name`.
+/// The second `impl` is for [`TypeName`] in `Name`. The type given after the `where`
+/// needs to match the type given in the first `impl`. However, in the second impl
+/// the `T` is a generic for a name not the generic for the type. That's why
+/// `T::Nameable` is used instead of `T`.
#[doc(hidden)]
#[macro_export]
macro_rules! nameable {
{
- $vis:vis [$a:lifetime, $lt:lifetime $(, $($generic:ident)*)?]
+ $vis:vis struct $name:ident[$a:lifetime, $lt:lifetime $(, $($generic:ident),* $(,)?)?];
- $type:ty
- where {$($bound:tt)*}
+ impl $([$($name_generics:tt)*])? for $type:ty where {$($nameable_bound:tt)*}
} => {
$crate::any::nameable! {
- $vis [$a, $lt $(, $($generic)*)?]
-
- $type
- where {$($bound)*}
+ $vis struct $name[$a, $lt $(, $($generic),*)?];
- $type
- where {$($bound)*}
+ impl $([$($name_generics)*])? for $type where {$($nameable_bound)*}
+ impl $([$($name_generics)*])? where $type {$($nameable_bound)*}
}
};
{
- $vis:vis [$a:lifetime, $lt:lifetime $(, $($generic:ident)*)?]
+ $vis:vis struct $name:ident[$a:lifetime, $lt:lifetime $(, $($generic:ident),* $(,)?)?];
- $type:ty
- where {$($bound:tt)*}
+ impl $([$($name_generics:tt)*])? for $type:ty where {$($nameable_bound:tt)*}
- $type2:ty
- where {$($bound2:tt)*}
+ impl $([$($nameable_generics:tt)*])? where $nameable_type:ty {$($name_bound:tt)*}
} => {
const _: () = {
- impl<$a, $lt $(, $($generic: $crate::any::TypeNameable<$a, $lt>)*)?>
+ $vis struct $name $(< $($generic: ?Sized),* >)?(
+ ::core::marker::PhantomData<fn() -> ($( $(*const $generic,)* )?)>
+ );
+
+ impl<$a, $lt $(, $($generic)*)?>
$crate::any::TypeNameable<$a, $lt> for $type
where
- $($bound)*
+ $($nameable_bound)*
{
- type Name = Name$(<$($generic::Name),*>)?;
+ type Name = $name $(<$($name_generics)*>)?;
}
- $vis struct Name$(< $($generic: ?Sized),* >)?(
- ::core::marker::PhantomData<fn() -> ($( $(*const $generic,)* )?)>
- );
-
- impl<$a, $lt $(, $($generic: $crate::any::TypeName<$a, $lt>)*)?>
- $crate::any::TypeName<$a, $lt> for Name$(<$($generic),*>)?
+ impl<$a, $lt $(, $($generic),*)?>
+ $crate::any::TypeName<$a, $lt> for Name$(<$($nameable_generics)*>)?
where
- $($bound2)*
+ $($name_bound)*
{
- type Nameable = $type2;
+ type Nameable = $nameable_type;
}
};
};
@@ -65,85 +131,77 @@ macro_rules! nameable {
#[doc(inline)]
pub use nameable;
-pub struct Owned<T: ?Sized>(pub T);
-
-const _: () = {
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
-
- impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for Owned<T> {
- type Name = Name<T>;
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T::Name] for &'lt T where {
+ T: TypeNameable<'a, 'lt> + ?Sized, T::Name: Sized, 'lt: 'a
}
-
- impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> {
- type Nameable = Owned<T>;
+ impl [T] where &'lt T::Nameable {
+ T: TypeName<'a, 'lt>, T::Nameable: 'lt, 'lt: 'a
}
-};
-
-pub struct Borrowed<'lt, T: ?Sized>(pub &'lt T);
-
-const _: () = {
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
+}
- impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeNameable<'a, 'lt> for Borrowed<'lt, T> {
- type Name = Name<T>;
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T::Name] for &'lt mut T where {
+ T: TypeNameable<'a, 'lt> + ?Sized, T::Name: Sized, 'lt: 'a
}
-
- impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> {
- type Nameable = Borrowed<'lt, T>;
+ impl [T] where &'lt mut T::Nameable {
+ T: TypeName<'a, 'lt>, T::Nameable: 'lt, 'lt: 'a
}
-};
-
-pub struct TempBorrowed<'a, T: ?Sized>(pub &'a T);
-
-const _: () = {
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
+}
- impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for TempBorrowed<'a, T> {
- type Name = Name<T>;
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T::Name] for *const T where {
+ T: TypeNameable<'a, 'lt> + ?Sized, T::Name: Sized
}
-
- impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> {
- type Nameable = TempBorrowed<'a, T>;
+ impl [T] where *const T::Nameable {
+ T: TypeName<'a, 'lt>
}
-};
-
-pub struct BorrowedMut<'lt, T: ?Sized>(pub &'lt mut T);
-
-const _: () = {
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
+}
- impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeNameable<'a, 'lt> for BorrowedMut<'lt, T> {
- type Name = Name<T>;
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T::Name] for *mut T where {
+ T: TypeNameable<'a, 'lt> + ?Sized, T::Name: Sized
}
-
- impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> {
- type Nameable = BorrowedMut<'lt, T>;
+ impl [T] where *mut T::Nameable {
+ T: TypeName<'a, 'lt>
}
-};
-
-pub struct TempBorrowedMut<'lt, T: ?Sized>(pub &'lt mut T);
-
-const _: () = {
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
+}
- impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for TempBorrowedMut<'a, T> {
- type Name = Name<T>;
+#[cfg(feature = "alloc")]
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T::Name] for Box<T> where {
+ T: TypeNameable<'a, 'lt> + ?Sized, T::Name: Sized
}
-
- impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> {
- type Nameable = TempBorrowedMut<'a, T>;
+ impl [T] where Box<T::Nameable> {
+ T: TypeName<'a, 'lt>
}
-};
-
-// box here
+}
+/// [`TypeId`][core::any::TypeId] with a lifetime generic `'lt`.
+///
+/// This allows comparing types that contain zero or one lifetimes.
+/// When `LtTypeId::of::<A>() == LtTypeId::of::<B>()` then `A` is `B`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
pub struct LtTypeId<'lt> {
+ /// Invariant over `'lt` for the eq check to be correct.
+ /// The borrow checker is checking that the lifetimes of the type
+ /// IDs are the same instead of doing it at runtime, which we can't do.
_marker: PhantomData<fn(&'lt ()) -> &'lt ()>,
+
+ /// The type ID of the name type of the type.
name_id: core::any::TypeId,
}
impl<'lt> LtTypeId<'lt> {
+ /// Get the ID of a type.
+ ///
+ /// The type must implement [`TypeNameable`]. Note, the `'a` lifetime is **not**
+ /// tracked by the [`LtTypeId`], only the `'lt` lifetime is.
pub fn of<'a, T: ?Sized + TypeNameable<'a, 'lt>>() -> Self {
LtTypeId {
_marker: PhantomData,
@@ -152,21 +210,40 @@ impl<'lt> LtTypeId<'lt> {
}
}
-pub unsafe trait LtAny<'lt> {
+/// [`Any`][core::any::Any] with a lifetime generic `'lt`.
+///
+/// This trait is implemented on all types that implement
+/// [`TypeNameable`]. It is not possible to implement this trait manually.
+///
+/// Like [`Any`][core::any::Any] this trait can be used as a trait object with
+/// downcasting.
+pub trait LtAny<'lt>: sealed::Sealed<'lt> {
+ /// Get the [`LtTypeId`] of the type of `self`.
fn type_id(&self) -> LtTypeId<'lt>;
}
-unsafe impl<'a, 'lt, T: ?Sized + TypeNameable<'a, 'lt>> LtAny<'lt> for T {
+// Prevent any impls except the following.
+mod sealed {
+ use super::*;
+
+ pub trait Sealed<'lt> {}
+
+ impl<'a, 'lt, T: ?Sized + TypeNameable<'a, 'lt>> Sealed<'lt> for T {}
+}
+
+impl<'a, 'lt, T: ?Sized + TypeNameable<'a, 'lt>> LtAny<'lt> for T {
fn type_id(&self) -> LtTypeId<'lt> {
LtTypeId::of::<T>()
}
}
impl<'a, 'lt> dyn LtAny<'lt> + 'a {
+ /// Check if `self` is of type `T`.
pub fn is<T: ?Sized + TypeNameable<'a, 'lt>>(&self) -> bool {
LtTypeId::of::<T>() == self.type_id()
}
+ /// Downcast a `&dyn LtAny<'lt>` into a `&T`.
pub fn downcast_ref<T: TypeNameable<'a, 'lt>>(&self) -> Option<&T> {
if self.is::<T>() {
Some(unsafe { &*(self as *const dyn LtAny<'lt> as *const T) })
@@ -175,6 +252,7 @@ impl<'a, 'lt> dyn LtAny<'lt> + 'a {
}
}
+ /// Downcast a `&mut dyn LtAny<'lt>` into a `&mut T`.
pub fn downcast_mut<T: TypeNameable<'a, 'lt>>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
Some(unsafe { &mut *(self as *mut dyn LtAny<'lt> as *mut T) })
@@ -183,6 +261,7 @@ impl<'a, 'lt> dyn LtAny<'lt> + 'a {
}
}
+ /// Downcast a `Box<dyn LtAny<'lt>>` into a `Box<T>`.
#[cfg(feature = "alloc")]
pub fn downcast_box<T: TypeNameable<'a, 'lt>>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
@@ -196,17 +275,88 @@ impl<'a, 'lt> dyn LtAny<'lt> + 'a {
}
}
+/// Dynamic trait lookup.
+///
+/// This trait allows looking up the trait object form of `self` for a
+/// given trait object `id`. This is similar to upcasting to the trait given
+/// by `id` if [`AnyTrait`] had every trait as a super bound.
+///
+/// ```
+/// use treaty::any::{AnyTrait, any_trait, nameable};
+///
+/// // Create a test value.
+/// let my_num = MyNum(42);
+///
+/// // Cast to be a AnyTrait trait object.
+/// // Now we don't know the type.
+/// let anything: &dyn AnyTrait<'_> = &my_num;
+///
+/// // We can still upcast to an impl of ToNum.
+/// let to_num_object: &dyn ToNum = anything.upcast().unwrap();
+///
+/// assert_eq!(to_num_object.num(), 42);
+///
+/// // === Type Setup ===
+///
+/// // An example trait.
+/// trait ToNum {
+/// fn num(&self) -> i32;
+/// }
+///
+/// // Make the trait object nameable.
+/// nameable! {
+/// struct Name['a, 'ctx];
+/// impl for dyn ToNum + 'a where { }
+/// }
+///
+/// // An example struct.
+/// struct MyNum(i32);
+///
+/// // The example struct impls the example trait.
+/// impl ToNum for MyNum {
+/// fn num(&self) -> i32 {
+/// self.0
+/// }
+/// }
+///
+/// // Allow the example struct's trait impls to be looked up at runtime.
+/// // Here the only trait that can be looked up is ToNum as its the only
+/// // one in the list.
+/// any_trait! {
+/// impl['a, 'ctx] MyNum = [dyn ToNum + 'a];
+/// }
+/// ```
pub trait AnyTrait<'lt> {
+ /// Upcast a borrow to the given trait object.
+ ///
+ /// Use the `<dyn AnyTrait>::upcast()` helper method instead, if possible.
+ ///
+ /// If `self` doesn't support upcasting to the requested type
+ /// then `None` is returned. The returned trait object is type erased so this trait
+ /// is object safe.
fn upcast_to_id<'a>(&'a self, id: LtTypeId<'lt>) -> Option<IndirectLtAny<'a, 'lt, Ref>>
where
'lt: 'a;
+ /// Upcast a mutable borrow to the given trait object.
+ ///
+ /// Use the `<dyn AnyTrait>::upcast_mut()` helper method instead, if possible.
+ ///
+ /// If `self` doesn't support upcasting to the requested type
+ /// then `None` is returned. The returned trait object is type erased so this trait
+ /// is object safe.
fn upcast_to_id_mut<'a>(&'a mut self, id: LtTypeId<'lt>) -> Option<IndirectLtAny<'a, 'lt, Mut>>
where
'lt: 'a;
}
impl<'lt> dyn AnyTrait<'lt> + '_ {
+ /// Upcast a borrow to the given trait object type.
+ ///
+ /// This should be used instead of [`upcast_to_id`][AnyTrait::upcast_to_id]
+ /// as it automatically downcasts the returned [`IndirectLtAny`].
+ ///
+ /// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
pub fn upcast<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(&'a self) -> Option<&'a Trait> {
self.upcast_to_id(LtTypeId::of::<Trait>())
.map(|object| match object.downcast::<Trait>() {
@@ -220,6 +370,12 @@ impl<'lt> dyn AnyTrait<'lt> + '_ {
})
}
+ /// Upcast a mutable borrow to the given trait object type.
+ ///
+ /// This should be used instead of [`upcast_to_id_mut`][AnyTrait::upcast_to_id]
+ /// as it automatically downcasts the returned [`IndirectLtAny`].
+ ///
+ /// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
pub fn upcast_mut<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(
&'a mut self,
) -> Option<&'a mut Trait> {
@@ -228,7 +384,7 @@ impl<'lt> dyn AnyTrait<'lt> + '_ {
Ok(object) => object,
Err(object) => panic!(
"Unexpected trait object. This means a bad impl of \
- `upcast_to_id`. Expected: {:?}, Got {:?}",
+ `upcast_to_id_mut`. Expected: {:?}, Got {:?}",
LtTypeId::of::<Trait>(),
object.id()
),
@@ -236,6 +392,10 @@ impl<'lt> dyn AnyTrait<'lt> + '_ {
}
}
+/// Implement [`AnyTrait`] for a type.
+///
+/// This allows looking up trait objects from the provided list.
+/// See [`AnyTrait`] for an example.
#[doc(hidden)]
#[macro_export]
macro_rules! any_trait {
@@ -278,11 +438,19 @@ macro_rules! any_trait {
#[doc(inline)]
pub use any_trait;
+/// A type erased pointer like.
+///
+/// This acts like a `&dyn LtAny` except it is able to type erase another fat pointer.
+/// This allows type erasing pointers to trait objects. A [`IndirectLtAny`] cannot
+/// store an instance of itself.
+///
+/// The `I` generic is the flavor if pointer being used. It can be [`Ref`], [`Mut`], [`Boxed`], or
+/// a custom pointer type.
#[must_use]
pub struct IndirectLtAny<'a, 'lt: 'a, I: Indirect<'a>> {
info: fn() -> (LtTypeId<'lt>, unsafe fn(RawIndirect)),
indirect: RawIndirect,
- _marker: PhantomData<(I::ForT<fn(&'lt ()) -> &'lt ()>, PhantomPinned)>,
+ _marker: PhantomData<(I::ForT<fn(&'lt ()) -> &'lt ()>, PhantomPinned, *const ())>,
}
impl<'a, 'lt, I: Indirect<'a>> Drop for IndirectLtAny<'a, 'lt, I> {
@@ -336,14 +504,23 @@ impl<'a, 'lt, I: Indirect<'a>> IndirectLtAny<'a, 'lt, I> {
}
}
+/// A pointer like type.
+///
+/// For this trait the pointer like type must have the same size as a pointer.
pub unsafe trait Indirect<'a> {
+ /// Get the full type for a given `T`.
type ForT<T: ?Sized + 'a>: 'a;
+ /// Convert the pointer into a raw indirection.
fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect;
+ /// Convert a raw indirection back into the pointer.
unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T>;
}
+/// An opaque set of bytes the size of a fat pointer.
+///
+/// Repr wise this is exactly `MaybeUninit<[u8; { size of a fat pointer }]>`.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct RawIndirect(MaybeUninit<[u8; INDIRECT_SIZE]>);
@@ -352,6 +529,7 @@ const INDIRECT_SIZE: usize = core::mem::size_of::<usize>() * 2;
trait Helper {}
+/// Marker type for [`IndirectLtAny`] for a borrow indirection (`&T`).
pub enum Ref {}
const _: () = assert!(core::mem::size_of::<&dyn Helper>() <= core::mem::size_of::<RawIndirect>());
@@ -368,6 +546,7 @@ unsafe impl<'a> Indirect<'a> for Ref {
}
}
+/// Marker type for [`IndirectLtAny`] for a mutable borrow indirection (`&mut T`).
pub enum Mut {}
const _: () =
@@ -394,7 +573,7 @@ mod boxed {
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
- /// A `Box<T>` indirection.
+ /// Marker type for [`IndirectLtAny`] for a box indirection (`Box<T>`).
pub enum Boxed {}
const _: () =
diff --git a/src/any/static_wrapper.rs b/src/any/static_wrapper.rs
new file mode 100644
index 0000000..cd687ce
--- /dev/null
+++ b/src/any/static_wrapper.rs
@@ -0,0 +1,60 @@
+//! Wrapper types that impl [`TypeNameable`] when their generic type is `'static`.
+
+use super::*;
+
+/// Impl of [`TypeNameable`] for `'static` types that are owned (`T`).
+pub struct OwnedStatic<T: ?Sized>(pub T);
+
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for OwnedStatic<T> where { T: 'static }
+ impl [T] where OwnedStatic<T> { T: 'static }
+}
+
+/// Impl of [`TypeNameable`] for `'static` types that are borrowed (`&'lt T`).
+pub struct BorrowedStatic<'lt, T: ?Sized>(pub &'lt T);
+
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for BorrowedStatic<'lt, T> where { T: 'static, 'lt: 'a }
+ impl [T] where BorrowedStatic<'lt, T> { T: 'static, 'lt: 'a }
+}
+
+/// Impl of [`TypeNameable`] for `'static` types that are temporarily borrowed (`&'a T`).
+pub struct TempBorrowedStatic<'a, T: ?Sized>(pub &'a T);
+
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for TempBorrowedStatic<'a, T> where { T: 'static }
+ impl [T] where TempBorrowedStatic<'a, T> { T: 'static }
+}
+
+/// Impl of [`TypeNameable`] for `'static` types that are borrowed mutably (`&'lt mut T`).
+pub struct BorrowedMutStatic<'lt, T: ?Sized>(pub &'lt mut T);
+
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for BorrowedMutStatic<'lt, T> where { T: 'static, 'lt: 'a }
+ impl [T] where BorrowedMutStatic<'lt, T> { T: 'static, 'lt: 'a }
+}
+
+/// Impl of [`TypeNameable`] for `'static` types that are temporarily borrowed mutably (`&'a mut T`).
+pub struct TempBorrowedMutStatic<'a, T: ?Sized>(pub &'a mut T);
+
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for TempBorrowedMutStatic<'a, T> where { T: 'static }
+ impl [T] where TempBorrowedMutStatic<'a, T> { T: 'static }
+}
+
+/// Impl of [`TypeNameable`] for `'static` types that are in a [`Box`] (`Box<T>`).
+#[cfg(feature = "alloc")]
+pub struct BoxedStatic<T: ?Sized>(pub Box<T>);
+
+#[cfg(feature = "alloc")]
+nameable! {
+ pub struct Name['a, 'lt, T];
+ impl [T] for BoxedStatic<T> where { T: 'static }
+ impl [T] where BoxedStatic<T> { T: 'static }
+}
+
diff --git a/src/lib.rs b/src/lib.rs
index 03e8725..e632612 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,7 @@ extern crate alloc;
pub mod any;
// mod build;
// pub mod builtins;
-pub mod protocol;
+// pub mod protocol;
pub mod symbol;
// mod walk;