cleaned up the any module
Konnor Andrews 2024-04-13
parent 15cbd6f · commit 108c74a
-rw-r--r--Cargo.toml1
-rw-r--r--src/any.rs585
-rw-r--r--src/any/indirect.rs237
-rw-r--r--src/any/static_wrapper.rs189
-rw-r--r--src/any/type_name_id.rs156
-rw-r--r--src/build/builders/debug.rs12
-rw-r--r--src/hkt.rs143
-rw-r--r--src/mock/builder.rs22
-rw-r--r--src/mock/protocol/value.rs18
-rw-r--r--src/protocol/visitor/recoverable.rs4
-rw-r--r--src/protocol/visitor/request_hint.rs4
-rw-r--r--src/protocol/visitor/sequence.rs4
-rw-r--r--src/protocol/visitor/tag.rs4
-rw-r--r--src/protocol/visitor/value.rs16
-rw-r--r--src/protocol/walker/hint.rs13
-rw-r--r--src/walk/walkers/core/struct.rs17
16 files changed, 925 insertions, 500 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 18ca4fd..1f09357 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ std = ["alloc", "serde?/std"]
alloc = ["serde?/alloc"]
serde = ["dep:serde"]
mock = ["std", "dep:mockall"]
+better_errors = []
[dev-dependencies]
macro_rules_attribute = "0.2.0"
diff --git a/src/any.rs b/src/any.rs
index 72a0c5f..da0f369 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -1,48 +1,52 @@
//! 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.
+//! The `AnyTrait` trait provides dynamic upcasting to trait objects.
+pub mod indirect;
pub mod static_wrapper;
+mod type_name_id;
use crate::{bijective_higher_ranked_trait, bijective_higher_ranked_type};
-use core::{
- any::TypeId,
- marker::{PhantomData, PhantomPinned},
- mem::{ManuallyDrop, MaybeUninit},
-};
+use core::marker::PhantomData;
+
+pub use type_name_id::*;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
bijective_higher_ranked_trait! {
- pub type class MaybeSized['lt][]: [for<'a>]
+ /// Higher ranked types with a context `'ctx` lifetime.
+ ///
+ /// Its recommended to name types of this class with a `Dyn` prefix.
+ /// This prefix was chosen because most lower types used in treaty are trait objects.
+ ///
+ /// This is most important for trait objects. For example `dyn MyTrait<'ctx> + 'a` this
+ /// type has a "extra" `'a` lifetime for how long its valid for. This higher ranked type class
+ /// allows naming the trait object type without a `'a` being given.
+ pub type class WithContextLt['ctx][]: {} [for<'a>]
}
bijective_higher_ranked_trait! {
- pub type class TypeName[][]: {'static} [for<'lt> MaybeSized::Trait<'lt> + Send]
+ /// Higher ranked types that are `'static`.
+ ///
+ /// Types of this class can usually be sealed as they don't need to be named directly.
+ ///
+ /// Higher ranked types of this form have a [`TypeId`] associated with them.
+ /// This allows them to be used as a name for lifetime containing types.
+ ///
+ /// This type class has members in the [`WithContextLt`] higher ranked type class.
+ /// To get a concrete type two lowerings need to be applied to inject two lifetimes.
+ /// One for the context lifetime, and one for the lifetime of the concrete type.
+ pub type class TypeName[][]: {'static} [for<'ctx> WithContextLt::MemberType<'ctx> + Send]
}
bijective_higher_ranked_type! {
- pub type DynRef['lt][][T['lt][]]: MaybeSized['lt][]
+ /// Higher ranked type for borrows `&T`.
+ ///
+ /// The borrow gets the `'a` lifetime, not the `'ctx` lifetime.
+ pub type DynRef['ctx][][T['ctx][]]: WithContextLt['ctx][]
for<'a>
- (&'a MaybeSized::T<'a, 'lt, T>)
+ (&'a WithContextLt::T<'a, 'ctx, T>)
(&'a T)
where {
T: ?Sized
@@ -51,18 +55,21 @@ bijective_higher_ranked_type! {
bijective_higher_ranked_type! {
pub type [][][T[][]]: TypeName[][]
- for<'lt>
- (DynRef<'lt, TypeName::T<'lt, T>>)
- (DynRef<'lt, T>)
+ for<'ctx>
+ (DynRef<'ctx, TypeName::T<'ctx, T>>)
+ (DynRef<'ctx, T>)
where {
T: ?Sized
}
}
bijective_higher_ranked_type! {
- pub type DynMut['lt][][T['lt][]]: MaybeSized['lt][]
+ /// Higher ranked type for mutable borrows `&mut T`.
+ ///
+ /// The borrow gets the `'a` lifetime, not the `'ctx` lifetime.
+ pub type DynMut['ctx][][T['ctx][]]: WithContextLt['ctx][]
for<'a>
- (&'a mut MaybeSized::T<'a, 'lt, T>)
+ (&'a mut WithContextLt::T<'a, 'ctx, T>)
(&'a mut T)
where {
T: ?Sized
@@ -71,9 +78,9 @@ bijective_higher_ranked_type! {
bijective_higher_ranked_type! {
pub type [][][T[][]]: TypeName[][]
- for<'lt>
- (DynMut<'lt, TypeName::T<'lt, T>>)
- (DynMut<'lt, T>)
+ for<'ctx>
+ (DynMut<'ctx, TypeName::T<'ctx, T>>)
+ (DynMut<'ctx, T>)
where {
T: ?Sized
}
@@ -81,9 +88,12 @@ bijective_higher_ranked_type! {
#[cfg(feature = "alloc")]
bijective_higher_ranked_type! {
- pub type DynBox['lt][][T['lt][]]: MaybeSized['lt][]
+ /// Higher ranked type for boxes `Box<T>`.
+ ///
+ /// A [`Box`] doesn't need either lifetime.
+ pub type DynBox['ctx][][T['ctx][]]: WithContextLt['ctx][]
for<'a>
- (Box<MaybeSized::T<'a, 'lt, T>>)
+ (Box<WithContextLt::T<'a, 'ctx, T>>)
(Box<T>)
where {
T: ?Sized
@@ -93,134 +103,14 @@ bijective_higher_ranked_type! {
#[cfg(feature = "alloc")]
bijective_higher_ranked_type! {
pub type [][][T[][]]: TypeName[][]
- for<'lt>
- (DynBox<'lt, TypeName::T<'lt, T>>)
- (DynBox<'lt, T>)
+ for<'ctx>
+ (DynBox<'ctx, TypeName::T<'ctx, T>>)
+ (DynBox<'ctx, T>)
where {
T: ?Sized
}
}
-/// [`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,
-
- name: &'static str,
-}
-
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
-pub struct ForAnyTypeId {
- /// The type ID of the name type of the type.
- name_id: core::any::TypeId,
-
- name: &'static str,
-}
-
-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<T: ?Sized + TypeName::Member<'lt>>() -> Self {
- LtTypeId {
- _marker: PhantomData,
- name_id: core::any::TypeId::of::<TypeName::HigherRanked<'lt, T>>(),
- name: core::any::type_name::<T>(),
- }
- }
-
- /// Get the type ID of the static form.
- ///
- /// This will be the same for all lifetimes.
- pub fn as_type_id(&self) -> ForAnyTypeId {
- ForAnyTypeId {
- name_id: self.name_id,
- name: self.name,
- }
- }
-}
-
-impl<'lt> core::fmt::Display for LtTypeId<'lt> {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- core::fmt::Display::fmt(self.name, f)
- }
-}
-
-/// [`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>;
-}
-
-// Prevent any impls except the following.
-mod sealed {
- use super::*;
-
- pub trait Sealed<'lt> {}
-
- impl<'lt, T: ?Sized + TypeName::Member<'lt>> Sealed<'lt> for T {}
-}
-
-impl<'lt, T: ?Sized + TypeName::Member<'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 + TypeName::Member<'lt>>(&self) -> bool {
- LtTypeId::of::<T>() == self.type_id()
- }
-
- /// Downcast a `&dyn LtAny<'lt>` into a `&T`.
- pub fn downcast_ref<T: TypeName::Member<'lt>>(&self) -> Option<&T> {
- if self.is::<T>() {
- Some(unsafe { &*(self as *const dyn LtAny<'lt> as *const T) })
- } else {
- None
- }
- }
-
- /// Downcast a `&mut dyn LtAny<'lt>` into a `&mut T`.
- pub fn downcast_mut<T: TypeName::Member<'lt>>(&mut self) -> Option<&mut T> {
- if self.is::<T>() {
- Some(unsafe { &mut *(self as *mut dyn LtAny<'lt> as *mut T) })
- } else {
- None
- }
- }
-
- /// Downcast a `Box<dyn LtAny<'lt>>` into a `Box<T>`.
- #[cfg(feature = "alloc")]
- pub fn downcast_box<T: TypeName::Member<'lt>>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
- if self.is::<T>() {
- Ok(unsafe {
- let raw: *mut dyn LtAny<'lt> = Box::into_raw(self);
- Box::from_raw(raw as *mut T)
- })
- } else {
- Err(self)
- }
- }
-}
-
/// Dynamic trait lookup.
///
/// This trait allows looking up the trait object form of `self` for a
@@ -272,7 +162,7 @@ impl<'a, 'lt> dyn LtAny<'lt> + 'a {
/// impl['a, 'ctx] MyNum = [dyn ToNum + 'a];
/// }
/// ```
-pub trait AnyTrait<'lt> {
+pub trait AnyTrait<'ctx> {
/// Upcast a borrow to the given trait object.
///
/// Use the `<dyn AnyTrait>::upcast()` helper method instead, if possible.
@@ -280,9 +170,12 @@ pub trait AnyTrait<'lt> {
/// 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>>
+ fn upcast_to_id<'a>(
+ &'a self,
+ id: TypeNameId,
+ ) -> Option<AnyTraitObject<'a, 'ctx, indirect::Ref>>
where
- 'lt: 'a;
+ 'ctx: 'a;
/// Upcast a mutable borrow to the given trait object.
///
@@ -291,52 +184,53 @@ pub trait AnyTrait<'lt> {
/// 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: 'b, 'b>(
+ fn upcast_to_id_mut<'a>(
&'a mut self,
- id: LtTypeId<'lt>,
- ) -> Option<IndirectLtAny<'b, 'lt, Mut>>
+ id: TypeNameId,
+ ) -> Option<AnyTraitObject<'a, 'ctx, indirect::Mut>>
where
- 'lt: 'a;
+ 'ctx: 'a;
}
-impl<'lt> dyn AnyTrait<'lt> + Send + '_ {
+impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + 'b {
/// 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`].
+ /// as it automatically downcasts the returned [`AnyTraitObject`].
///
- /// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
- pub fn upcast<'a, Trait: ?Sized + TypeName::Member<'lt>>(
+ /// If the returned [`AnyTraitObject`] is the wrong type, then a panic happens.
+ pub fn upcast<'a, Trait: ?Sized + TypeName::LowerType<'ctx>>(
&'a self,
- ) -> Option<&'a MaybeSized::T<'a, 'lt, Trait>> {
- self.upcast_to_id(LtTypeId::of::<Trait>())
- .map(|object| match object.downcast::<Trait>() {
+ ) -> Option<&'a WithContextLt::T<'a, 'ctx, Trait>> {
+ self.upcast_to_id(TypeNameId::of::<Trait>()).map(|object| {
+ match object.downcast() {
Ok(object) => object,
Err(object) => panic!(
"Unexpected trait object. This means a bad impl of \
`upcast_to_id`. Expected: {:?}, Got {:?}",
- LtTypeId::of::<Trait>(),
+ TypeNameId::of::<Trait>(),
object.id()
),
- })
+ }
+ })
}
/// 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`].
+ /// as it automatically downcasts the returned [`AnyTraitObject`].
///
- /// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
- pub fn upcast_mut<'a, Trait: ?Sized + TypeName::Member<'lt>>(
+ /// If the returned [`AnyTraitObject`] is the wrong type, then a panic happens.
+ pub fn upcast_mut<'a, Trait: ?Sized + TypeName::LowerType<'ctx>>(
&'a mut self,
- ) -> Option<&'a mut MaybeSized::T<'a, 'lt, Trait>> {
- self.upcast_to_id_mut(LtTypeId::of::<Trait>())
- .map(|object| match object.downcast::<Trait>() {
+ ) -> Option<&'a mut WithContextLt::T<'a, 'ctx, Trait>> {
+ self.upcast_to_id_mut(TypeNameId::of::<Trait>())
+ .map(|object| match object.downcast() {
Ok(object) => object,
Err(object) => panic!(
"Unexpected trait object. This means a bad impl of \
`upcast_to_id_mut`. Expected: {:?}, Got {:?}",
- LtTypeId::of::<Trait>(),
+ TypeNameId::of::<Trait>(),
object.id()
),
})
@@ -351,7 +245,12 @@ impl<'lt> dyn AnyTrait<'lt> + Send + '_ {
#[macro_export]
macro_rules! any_trait {
{
- impl[$lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?] $(else $fallback:path)? $(where $($bound:tt)*)?
+ impl[$lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?]
+ else {
+ let $id:ident;
+ $($fallback:tt)*
+ }
+ $(where $($bound:tt)*)?
} => {
impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name
$(where $($bound)*)?
@@ -359,92 +258,116 @@ macro_rules! any_trait {
#[inline]
fn upcast_to_id<'__>(
&'__ self,
- id: $crate::any::LtTypeId<$lt>
- ) -> ::core::option::Option<$crate::any::IndirectLtAny<'__, $lt, $crate::any::Ref>>
+ id: $crate::any::TypeNameId
+ ) -> ::core::option::Option<$crate::any::AnyTraitObject<'__, $lt, $crate::any::indirect::Ref>>
where
$lt: '__
{
+ // This match should be optimized well by llvm.
match id {
- $(id if id == $crate::any::LtTypeId::of::<$protocol>()
- => ::core::option::Option::Some($crate::any::IndirectLtAny::<'__, $lt, _>::new::<$protocol>(self as _)),)*
- _ => {
- $($fallback(id);)?
- ::core::option::Option::None
+ $(id if id == $crate::any::TypeNameId::of::<$protocol>()
+ => ::core::option::Option::Some($crate::any::AnyTraitObject::<'__, $lt, _>::new::<
+ $crate::any::WithContextLt::T<'__, $lt, $protocol>
+ >(self as _)),)*
+ $id => {
+ $($fallback)*
}
}
}
#[inline]
- fn upcast_to_id_mut<'__: '___, '___>(
+ fn upcast_to_id_mut<'__>(
&'__ mut self,
- id: $crate::any::LtTypeId<$lt>
- ) -> ::core::option::Option<$crate::any::IndirectLtAny<'___, $lt, $crate::any::Mut>>
+ id: $crate::any::TypeNameId
+ ) -> ::core::option::Option<$crate::any::AnyTraitObject<'__, $lt, $crate::any::indirect::Mut>>
where
$lt: '__
{
+ // This match should be optimized well by llvm.
match id {
- $(id if id == $crate::any::LtTypeId::of::<$protocol>()
- => ::core::option::Option::Some($crate::any::IndirectLtAny::<'___, $lt, _>::new::<$protocol>(self as _)),)*
- _ => {
- $($fallback(id);)?
- ::core::option::Option::None
+ $(id if id == $crate::any::TypeNameId::of::<$protocol>()
+ => ::core::option::Option::Some($crate::any::AnyTraitObject::<'__, $lt, _>::new::<
+ $crate::any::WithContextLt::T<'__, $lt, $protocol>
+ >(self as _)),)*
+ $id => {
+ $($fallback)*
}
}
}
}
};
+ {
+ impl[$lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?]
+ $(where $($bound:tt)*)?
+ } => {
+ $crate::any::any_trait! {
+ impl[$lt $($generic)*] $name = [$($protocol),*]
+ else {
+ // Always answer no in the fallback branch if no fallback was given.
+ let _id;
+ ::core::option::Option::None
+ } $(where $($bound)*)?
+ }
+ }
}
#[doc(inline)]
pub use any_trait;
-/// A type erased pointer like.
+use self::indirect::{sealed::RawIndirect, Indirect};
+
+/// A double fat pointer.
+///
+/// This struct wraps a possibly fat pointer of type described by `I`, and adds
+/// an additional vtable to allow downcasting to a specific fat pointer.
+/// This type is similar to if `&dyn Any` was allowed to itself store unsized types like trait
+/// objects.
///
-/// 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 `'a` lifetime is the lifetime of the pointer, and the `'ctx` lifetime is a context lifetime
+/// the inner type can use. This type is always invariant over both lifetimes.
///
-/// The `I` generic is the flavor if pointer being used. It can be [`Ref`], [`Mut`], [`Boxed`], or
-/// a custom pointer type.
+/// `&'a dyn MyTrait<ctx>` becomes `AnyTraitObject<'a, 'ctx, Ref>`.
+///
+/// The `I` generic is the flavor if pointer being used. It can be [`Ref`] or [`Mut`].
#[must_use]
-pub struct IndirectLtAny<'a, 'lt: 'a, I: Indirect<'a>> {
- info: fn() -> (LtTypeId<'lt>, unsafe fn(RawIndirect)),
- indirect: RawIndirect,
+pub struct AnyTraitObject<'a, 'ctx: 'a, I: Indirect<'a>> {
+ /// The extra vtable pointer.
+ ///
+ /// The TypeNameId gives the TypeId of the T's type name.
+ /// This is unique per T minus the 'a and 'ctx lifetimes.
+ /// which means a `dyn Trait<'ctx> + 'a` can have a TypeNameId.
+ ///
+ /// The unsafe function is the drop impl for the pointer.
+ /// It must only be called once per RawIndirect value, and the value must not be used after the
+ /// call. Only a RawIndirect of the correct I type must be passed.
+ info: fn() -> TypeNameId,
+
+ /// The inner pointer value.
+ ///
+ /// This is some form of &T where T may be sized or not.
+ indirect: RawIndirect<'a, I>,
+
+ /// Extra type information for the type system.
_marker: PhantomData<(
- I::ForT<fn(&'lt (), &'a ()) -> (&'lt (), &'a ())>,
- PhantomPinned,
+ // Invariant over 'a and 'ctx, the TypeNameId doesn't track lifetimes so we have to do it
+ // here.
+ // https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns
+ fn(&'ctx ()) -> &'ctx (),
+ // Not Send or Sync.
*const (),
)>,
}
-impl<'a, 'lt, I: Indirect<'a>> Drop for IndirectLtAny<'a, 'lt, I> {
- fn drop(&mut self) {
- // We need to drop the stored value.
-
- // Lookup drop function.
- let (_, drop_fn) = (self.info)();
-
- // SAFETY: self.indirect is never touched again.
- // Additionally, we know that drop_fn is for this self.indirect because it was
- // made by Self::new.
- unsafe { drop_fn(self.indirect) };
- }
-}
-
-impl<'a, 'lt, I: Indirect<'a>> IndirectLtAny<'a, 'lt, I> {
- /// Wrap an indirection.
+impl<'a, 'ctx, I: Indirect<'a>> AnyTraitObject<'a, 'ctx, I> {
+ /// Type erase a pointer.
///
- /// The inner type `T` of the indirection is erased.
- pub fn new<T: ?Sized + TypeName::Member<'lt>>(
- indirect: I::ForT<MaybeSized::T<'a, 'lt, T>>,
- ) -> Self {
+ /// `T` doesn't need to be [`Sized`]. As such, a fat pointer can be passed to this function.
+ pub fn new<T: ?Sized + WithContextLt::LowerType<'a, 'ctx>>(indirect: I::ForT<T>) -> Self
+ where
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx>,
+ {
Self {
- info: || {
- (LtTypeId::of::<T>(), |raw| {
- // SAFETY: This is only called in the drop impl.
- unsafe { drop(I::from_raw::<MaybeSized::T<'a, 'lt, T>>(raw)) }
- })
- },
- indirect: I::into_raw(indirect),
+ info: TypeNameId::of_lower::<T>,
+ indirect: RawIndirect::new(indirect),
_marker: PhantomData,
}
}
@@ -453,139 +376,33 @@ impl<'a, 'lt, I: Indirect<'a>> IndirectLtAny<'a, 'lt, I> {
///
/// If the type of the stored value is different, then `self` is
/// returned as is.
- pub fn downcast<T: ?Sized + TypeName::Member<'lt>>(
+ pub fn downcast<T: ?Sized + WithContextLt::LowerType<'a, 'ctx>>(
self,
- ) -> Result<I::ForT<MaybeSized::T<'a, 'lt, T>>, Self> {
- let (id, _) = (self.info)();
-
- if id == LtTypeId::of::<T>() {
- Ok(unsafe { I::from_raw::<MaybeSized::T<'a, 'lt, T>>(self.indirect) })
+ ) -> Result<I::ForT<T>, Self>
+ where
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx>,
+ {
+ if self.id() == TypeNameId::of_lower::<T>() {
+ // SAFETY: We know that the type name type is unique per T because it is bijective.
+ // A self is only made in Self::new where the info is taken from T.
+ // If the check above passes then we know T must be the same minus the lifetimes.
+ // We know the lifetime 'ctx is correct because Self is invariant over it.
+ // RawIndirect makes sure that the 'a is correct by being invariant over it.
+ //
+ // See the tests at the bottom of the file for a proof that the type name is bijective
+ // to T.
+ Ok(unsafe { self.indirect.into_inner::<T>() })
} else {
Err(self)
}
}
/// Type ID of the stored value's `T`.
- pub fn id(&self) -> LtTypeId<'lt> {
- (self.info)().0
- }
-}
-
-/// 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]>);
-
-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>());
-
-unsafe impl<'a> Indirect<'a> for Ref {
- type ForT<T: ?Sized + 'a> = &'a T;
-
- fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect {
- unsafe { transmute::<&'a T, RawIndirect>(value) }
- }
-
- unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T> {
- unsafe { transmute::<RawIndirect, &'a T>(any) }
- }
-}
-
-/// Marker type for [`IndirectLtAny`] for a mutable borrow indirection (`&mut T`).
-pub enum Mut {}
-
-const _: () =
- assert!(core::mem::size_of::<&mut dyn Helper>() <= core::mem::size_of::<RawIndirect>());
-
-unsafe impl<'a> Indirect<'a> for Mut {
- type ForT<T: ?Sized + 'a> = &'a mut T;
-
- fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect {
- unsafe { transmute::<&'a mut T, RawIndirect>(value) }
- }
-
- unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T> {
- unsafe { transmute::<RawIndirect, &'a mut T>(any) }
+ pub fn id(&self) -> TypeNameId {
+ (self.info)()
}
}
-#[cfg(feature = "alloc")]
-pub use boxed::*;
-
-#[cfg(feature = "alloc")]
-mod boxed {
- use super::*;
-
- #[cfg(not(feature = "std"))]
- use alloc::boxed::Box;
-
- /// Marker type for [`IndirectLtAny`] for a box indirection (`Box<T>`).
- pub enum Boxed {}
-
- const _: () =
- assert!(core::mem::size_of::<Box<dyn Helper>>() <= core::mem::size_of::<RawIndirect>());
-
- unsafe impl<'a> Indirect<'a> for Boxed {
- type ForT<T: ?Sized + 'a> = Box<T>;
-
- fn into_raw<T: ?Sized + 'a>(value: Box<T>) -> RawIndirect {
- unsafe { transmute::<Box<T>, RawIndirect>(value) }
- }
-
- unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Box<T> {
- unsafe { transmute::<RawIndirect, Box<T>>(any) }
- }
- }
-}
-
-/// # Safety
-/// Same rules as [`core::mem::transmute()`].
-unsafe fn transmute<T, U>(value: T) -> U {
- // Create union type that can store a `T` or a `U`.
- // We can then use this to convert between them.
- //
- // The repr(C) layout forces no offset between `t` and `u` as talked about here
- // https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html#c-compatible-layout-repr-c
- #[repr(C)]
- union Transmute<T, U> {
- t: ManuallyDrop<T>,
- u: ManuallyDrop<U>,
- }
-
- // Create the union in the `T` state.
- let value = Transmute {
- t: ManuallyDrop::new(value),
- };
-
- // Read from the union in the `U` state.
- // SAFETY: This is safe because the caller has promised that `T` can be transmuted to `U`.
- // The following reference link talks about repr(C) unions being used this way.
- // https://doc.rust-lang.org/reference/items/unions.html#reading-and-writing-union-fields
- ManuallyDrop::into_inner(unsafe { value.u })
-}
-
#[cfg(test)]
mod test {
use crate::bijective_higher_ranked_type;
@@ -593,17 +410,17 @@ mod test {
use super::*;
#[test]
- fn implementer_macro() {
+ fn any_trait_macro_implements_the_trait() {
trait Z<'ctx> {
fn get(&self) -> i32;
}
bijective_higher_ranked_type! {
- type DynZ['ctx][]: MaybeSized['ctx][] for<'a> (dyn Z<'ctx> + 'a)
+ type DynZ['ctx][]: WithContextLt['ctx][] for<'a> (dyn Z<'ctx> + 'a)
}
bijective_higher_ranked_type! {
- type [][]: TypeName[][] for<'lt> (DynZ<'lt>)
+ type [][]: TypeName[][] for<'ctx> (DynZ<'ctx>)
}
struct X<'ctx>(&'ctx i32);
@@ -627,4 +444,46 @@ mod test {
.unwrap();
assert_eq!(y.get(), 42);
}
+
+ // The following proves that the higher ranked types are bijective using the type system.
+ //
+ // We have the type tower: T<'a, 'ctx> <-> DynT<'ctx> <-> NameT
+ // We want every T, DynT, NameT set to be unique.
+ //
+ // Assume there was a U that tried to use NameT in it's type tower:
+ // U<'a, 'ctx> <-> DynU<'ctx> <-> NameT
+ //
+ // If we traverse the type tower in this order: T -r-> A -r-> B -l-> C -l-> D
+ // where -r-> is a raise and -l-> is a lower, then if D is always T we know that no sequence
+ // U -r-> A2 -r-> B -l-> C2 -l-> D can exist exept where T == U. This is because B cannot
+ // have information about where it came from and still be the same B in the type system.
+ // The following makes sure that a U could never become a T by the raise then lower process.
+
+ // This proves that the bijective type names are really bijective.
+ fn _is_bijective_raise<'a, 'ctx: 'a, T>(
+ x: &WithContextLt::T<
+ 'a,
+ 'ctx,
+ TypeName::T<'ctx, TypeName::HigherRanked<'ctx, WithContextLt::HigherRanked<'a, 'ctx, T>>>,
+ >,
+ ) where
+ T: WithContextLt::LowerType<'a, 'ctx>,
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx>,
+ {
+ // If C -> B -> A -> B -> C (shown by this assignment), then C and A must be bijective.
+ let _y: &T = x;
+ }
+
+ // This proves that the bijective type names are really bijective.
+ fn _is_bijective_lower<'a, 'ctx: 'a, U>(
+ x: &TypeName::HigherRanked<
+ 'ctx,
+ WithContextLt::HigherRanked<'a, 'ctx, WithContextLt::T<'a, 'ctx, TypeName::T<'ctx, U>>>,
+ >,
+ ) where
+ U: TypeName::MemberType,
+ {
+ // If A -> B -> C -> B -> A (shown by this assignment), then A and C must be bijective.
+ let _y: &U = x;
+ }
}
diff --git a/src/any/indirect.rs b/src/any/indirect.rs
new file mode 100644
index 0000000..eef24f0
--- /dev/null
+++ b/src/any/indirect.rs
@@ -0,0 +1,237 @@
+//! Generic over borrow mutability.
+
+use core::mem::{ManuallyDrop, MaybeUninit};
+
+/// A higher kinded type.
+pub trait HigherKinded<'a> {
+ /// The type with `T` applied.
+ type ForT<T: ?Sized + 'a>: Unpin + 'a;
+}
+
+/// A pointer like type.
+///
+/// Allows being generic over `&T` and `&mut T`.
+///
+/// Implemented by marker types [`Ref`] and [`Mut`].
+pub trait Indirect<'a>: HigherKinded<'a> + sealed::Sealed<'a> {}
+
+pub(super) mod sealed {
+ use core::marker::PhantomData;
+
+ use super::*;
+
+ /// Sealed trait to prevent users from implementing Indirect and provides conversion
+ /// to and from a raw indirect.
+ pub trait Sealed<'a>: HigherKinded<'a> + Sized {
+ /// Convert the pointer into a raw indirection.
+ fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]>;
+
+ /// Convert a raw indirection back into the pointer.
+ ///
+ /// # Safety
+ /// `value` must have been created by `Self::into_raw`.
+ /// This function must not be called twice for the same `value`.
+ /// The type `T` must be the one given to `Self::into_raw`.
+ unsafe fn from_raw<T: ?Sized + 'a>(value: MaybeUninit<[u8; INDIRECT_SIZE]>) -> 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 }]>`.
+ #[repr(transparent)]
+ pub struct RawIndirect<'a, I> {
+ indirect: MaybeUninit<[u8; INDIRECT_SIZE]>,
+ _marker: PhantomData<fn(&'a ()) -> (&'a (), I)>,
+ }
+
+ impl<'a, I: Indirect<'a>> RawIndirect<'a, I> {
+ pub fn new<T: ?Sized>(indirect: I::ForT<T>) -> Self {
+ Self {
+ indirect: I::into_raw(indirect),
+ _marker: PhantomData,
+ }
+ }
+
+ /// # Safety
+ /// The type `T` must be the same one used in `Self::new`.
+ pub unsafe fn into_inner<T: ?Sized>(self) -> I::ForT<T> {
+ // SAFETY: indirect was created with this I's into_raw in Self::new.
+ // This function cannot be called twice because we take ownership of self and
+ // this type is not clone or copy.
+ // The caller makes sure that the T is the same.
+ // Also the lifetime 'a must be the same because Self is invariant over it.
+ unsafe {
+ I::from_raw(self.indirect)
+ }
+ }
+ }
+
+ /// Size of a fat pointer.
+ const INDIRECT_SIZE: usize = core::mem::size_of::<usize>() * 2;
+
+ /// Helper trait for double checking the sizes of fat pointers.
+ trait Helper {
+ fn run(&self);
+ }
+
+ const _: () =
+ assert!(core::mem::size_of::<&dyn Helper>() <= core::mem::size_of::<RawIndirect<'_, Ref>>());
+
+ // Borrow doesn't need to be dropped.
+ const _: () =
+ assert!(!core::mem::needs_drop::<&i32>());
+
+ const _: () = assert!(
+ core::mem::size_of::<&mut dyn Helper>() <= core::mem::size_of::<sealed::RawIndirect<'_, Mut>>()
+ );
+
+ // Mutable borrow doesn't need to be dropped.
+ const _: () =
+ assert!(!core::mem::needs_drop::<&mut i32>());
+
+ impl<'a> Sealed<'a> for Ref {
+ fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]> {
+ // SAFETY: A possibly fat borrow can be stores in a 2 usize wide maybe uninit array.
+ unsafe { transmute::<&'a T, MaybeUninit<[u8; INDIRECT_SIZE]>>(value) }
+ }
+
+ unsafe fn from_raw<T: ?Sized + 'a>(any: MaybeUninit<[u8; INDIRECT_SIZE]>) -> Self::ForT<T> {
+ // SAFETY: We know the value is from Self::into_raw because of the caller invariants.
+ unsafe { transmute::<MaybeUninit<[u8; INDIRECT_SIZE]>, &'a T>(any) }
+ }
+ }
+
+ impl<'a> Sealed<'a> for Mut {
+ fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> MaybeUninit<[u8; INDIRECT_SIZE]> {
+ // SAFETY: A possibly fat borrow can be stores in a 2 usize wide maybe uninit array.
+ unsafe { transmute::<&'a mut T, MaybeUninit<[u8; INDIRECT_SIZE]>>(value) }
+ }
+
+ unsafe fn from_raw<T: ?Sized + 'a>(any: MaybeUninit<[u8; INDIRECT_SIZE]>) -> Self::ForT<T> {
+ // SAFETY: We know the value is from Self::into_raw because of the caller invariants.
+ unsafe { transmute::<MaybeUninit<[u8; INDIRECT_SIZE]>, &'a mut T>(any) }
+ }
+ }
+}
+
+/// Marker type for [`AnyTraitObject`](super::AnyTraitObject) for a borrow `&T`.
+pub enum Ref {}
+
+impl<'a> HigherKinded<'a> for Ref {
+ type ForT<T: ?Sized + 'a> = &'a T;
+}
+
+impl<'a> Indirect<'a> for Ref {}
+
+/// Marker type for [`AnyTraitObject`](super::AnyTraitObject) for a mutable borrow `&mut T`.
+pub enum Mut {}
+
+impl<'a> HigherKinded<'a> for Mut {
+ type ForT<T: ?Sized + 'a> = &'a mut T;
+}
+
+impl<'a> Indirect<'a> for Mut {}
+
+/// # Safety
+/// Same rules as [`core::mem::transmute()`].
+unsafe fn transmute<T, U>(value: T) -> U {
+ // Create union type that can store a `T` or a `U`.
+ // We can then use this to convert between them.
+ //
+ // The repr(C) layout forces no offset between `t` and `u` as talked about here
+ // https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html#c-compatible-layout-repr-c
+ #[repr(C)]
+ union Transmute<T, U> {
+ t: ManuallyDrop<T>,
+ u: ManuallyDrop<U>,
+ }
+
+ // Create the union in the `T` state.
+ let value = Transmute {
+ t: ManuallyDrop::new(value),
+ };
+
+ // Read from the union in the `U` state.
+ // SAFETY: This is safe because the caller has promised that `T` can be transmuted to `U`.
+ // The following reference link talks about repr(C) unions being used this way.
+ // https://doc.rust-lang.org/reference/items/unions.html#reading-and-writing-union-fields
+ ManuallyDrop::into_inner(unsafe { value.u })
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ use sealed::RawIndirect;
+
+ #[test]
+ fn can_type_erase_borrow() {
+ let x = 42;
+ let y: &i32 = &x;
+ let z = RawIndirect::<Ref>::new(y);
+
+ // SAFETY: Same type as y which we made it from.
+ let w: &i32 = unsafe { z.into_inner() };
+
+ assert_eq!(w, y);
+ }
+
+ trait AsInt {
+ fn as_int(&self) -> i32;
+ }
+
+ impl AsInt for i32 {
+ fn as_int(&self) -> i32 {
+ *self
+ }
+ }
+
+ #[test]
+ fn can_type_erase_unsized_borrow() {
+ let x = 42;
+ let y: &dyn AsInt = &x;
+ let z = RawIndirect::<Ref>::new(y);
+
+ // SAFETY: Same type as y which we made it from.
+ let w: &i32 = unsafe { z.into_inner() };
+
+ assert_eq!(w.as_int(), x);
+ }
+
+ #[test]
+ fn can_type_erase_mut_borrow() {
+ let mut x = 42;
+ let y: &mut i32 = &mut x;
+ let z = RawIndirect::<Mut>::new(y);
+
+ // SAFETY: Same type as y which we made it from.
+ let w: &mut i32 = unsafe { z.into_inner() };
+
+ *w += 1;
+ assert_eq!(x, 43);
+ }
+
+ trait AddOne {
+ fn add_one(&mut self);
+ }
+
+ impl AddOne for i32 {
+ fn add_one(&mut self) {
+ *self += 1;
+ }
+ }
+
+ #[test]
+ fn can_type_erase_unsized_mut_borrow() {
+ let mut x = 42;
+ let y: &mut dyn AddOne = &mut x;
+ let z = RawIndirect::<Mut>::new(y);
+
+ // SAFETY: Same type as y which we made it from.
+ let w: &mut dyn AddOne = unsafe { z.into_inner() };
+
+ w.add_one();
+
+ assert_eq!(x, 43);
+ }
+}
diff --git a/src/any/static_wrapper.rs b/src/any/static_wrapper.rs
index 4acb200..4b238b9 100644
--- a/src/any/static_wrapper.rs
+++ b/src/any/static_wrapper.rs
@@ -1,162 +1,237 @@
-//! Wrapper types that impl [`TypeNameable`] when their generic type is `'static`.
+//! Wrapper types that impl [`TypeName`] when their generic type `T` is `'static`.
use super::*;
-/// Impl of [`TypeNameable`] for `'static` types that are owned (`T`).
+/// Owned static `T`.
#[derive(PartialEq, Clone, Copy, Debug)]
#[repr(transparent)]
pub struct OwnedStatic<T: ?Sized>(pub T);
-// bijective_higher_ranked_type! {
-// pub type DynOwnedStatic['lt][T][]: MaybeSized['lt][]
-// for<'a>
-// (OwnedStatic<T>)
-// where {
-// T: ?Sized + 'lt
-// }
-// }
-
+/// Higher ranked type for [`OwnedStatic`].
pub struct DynOwnedStatic<T: ?Sized>(PhantomData<fn() -> *const T>);
-impl<'a, 'lt, T: ?Sized + 'lt> MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>
+impl<'a, 'ctx, T: ?Sized + 'ctx> WithContextLt::LowerForLt<'a, 'ctx, &'a (&'ctx (),)>
for DynOwnedStatic<T>
{
type T = OwnedStatic<T>;
}
-impl<'a, 'lt, T: ?Sized + 'lt> MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)> for OwnedStatic<T> {
+impl<'a, 'ctx, T: ?Sized + 'ctx> WithContextLt::RaiseForLt<'a, 'ctx, &'a (&'ctx (),)>
+ for OwnedStatic<T>
+{
type HigherRanked = DynOwnedStatic<T>;
}
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
+ for<'ctx>
(DynOwnedStatic<T>)
where {
T: ?Sized + 'static
}
}
-/// Impl of [`TypeNameable`] for `'static` types that are borrowed (`&'lt T`).
+/// Borrowed static `T` for `'ctx`.
#[repr(transparent)]
-pub struct BorrowedStatic<'lt, T: ?Sized>(pub &'lt T);
+pub struct BorrowedStatic<'ctx, T: ?Sized>(pub &'ctx T);
bijective_higher_ranked_type! {
- pub type DynBorrowedStatic['lt][T]: MaybeSized['lt][]
+ /// Higher ranked type for [`BorrowedStatic`].
+ pub type DynBorrowedStatic['ctx][T]: WithContextLt['ctx][]
for<'a>
- (BorrowedStatic<'lt, T>)
+ (BorrowedStatic<'ctx, T>)
where {
- T: ?Sized + 'lt,
+ T: ?Sized + 'ctx,
}
}
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
- (DynBorrowedStatic<'lt, T>)
+ for<'ctx>
+ (DynBorrowedStatic<'ctx, T>)
where {
T: ?Sized + 'static
}
}
-/// Impl of [`TypeNameable`] for `'static` types that are temporarily borrowed (`&'a T`).
+/// Borrowed static `T` for `'a`.
#[repr(transparent)]
pub struct TempBorrowedStatic<'a, T: ?Sized>(pub &'a T);
bijective_higher_ranked_type! {
- pub type DynTempBorrowedStatic['lt][T]: MaybeSized['lt][]
+ /// Higher ranked type for [`TempBorrowedStatic`].
+ pub type DynTempBorrowedStatic['ctx][T]: WithContextLt['ctx][]
for<'a>
(TempBorrowedStatic<'a, T>)
where {
- T: ?Sized + 'lt,
+ T: ?Sized + 'ctx,
}
}
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
- (DynTempBorrowedStatic<'lt, T>)
+ for<'ctx>
+ (DynTempBorrowedStatic<'ctx, T>)
where {
T: ?Sized + 'static
}
}
-/// Impl of [`TypeNameable`] for `'static` types that are borrowed mutably (`&'lt mut T`).
+/// Mutably borrowed static `T` for `'ctx`.
#[repr(transparent)]
-pub struct BorrowedMutStatic<'lt, T: ?Sized>(pub &'lt mut T);
+pub struct BorrowedMutStatic<'ctx, T: ?Sized>(pub &'ctx mut T);
bijective_higher_ranked_type! {
- pub type DynBorrowedMutStatic['lt][T]: MaybeSized['lt][]
+ /// Higher ranked type for [`BorrowedMutStatic`].
+ pub type DynBorrowedMutStatic['ctx][T]: WithContextLt['ctx][]
for<'a>
- (BorrowedMutStatic<'lt, T>)
+ (BorrowedMutStatic<'ctx, T>)
where {
- T: ?Sized + 'lt,
+ T: ?Sized + 'ctx,
}
}
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
- (DynBorrowedMutStatic<'lt, T>)
+ for<'ctx>
+ (DynBorrowedMutStatic<'ctx, T>)
where {
T: ?Sized + 'static
}
}
-/// Impl of [`TypeNameable`] for `'static` types that are temporarily borrowed mutably (`&'a mut T`).
+/// Mutably borrowed static `T` for `'a`.
#[repr(transparent)]
pub struct TempBorrowedMutStatic<'a, T: ?Sized>(pub &'a mut T);
bijective_higher_ranked_type! {
- pub type DynTempBorrowedMutStatic['lt][T]: MaybeSized['lt][]
+ /// Higher ranked type for [`TempBorrowedMutStatic`].
+ pub type DynTempBorrowedMutStatic['ctx][T]: WithContextLt['ctx][]
for<'a>
(TempBorrowedMutStatic<'a, T>)
where {
- T: ?Sized + 'lt,
+ T: ?Sized + 'ctx,
}
}
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
- (DynTempBorrowedMutStatic<'lt, T>)
+ for<'ctx>
+ (DynTempBorrowedMutStatic<'ctx, T>)
where {
T: ?Sized + 'static
}
}
-/// Impl of [`TypeNameable`] for `'static` types that are in a [`Box`] (`Box<T>`).
+/// Boxed static `T`.
#[cfg(feature = "alloc")]
+#[repr(transparent)]
pub struct BoxedStatic<T: ?Sized>(pub Box<T>);
+/// Higher ranked type for [`BoxedStatic`].
#[cfg(feature = "alloc")]
-bijective_higher_ranked_type! {
- pub type DynBoxedStatic['lt][T]: MaybeSized['lt][]
- for<'a>
- (BoxedStatic<T>)
- where {
- T: ?Sized + 'lt,
- }
+pub struct DynBoxedStatic<T: ?Sized>(PhantomData<fn() -> *const T>);
+
+#[cfg(feature = "alloc")]
+impl<'a, 'ctx, T: ?Sized + 'ctx> WithContextLt::LowerForLt<'a, 'ctx, &'a (&'ctx (),)>
+ for DynBoxedStatic<T>
+{
+ type T = BoxedStatic<T>;
+}
+
+#[cfg(feature = "alloc")]
+impl<'a, 'ctx, T: ?Sized + 'ctx> WithContextLt::RaiseForLt<'a, 'ctx, &'a (&'ctx (),)>
+ for BoxedStatic<T>
+{
+ type HigherRanked = DynBoxedStatic<T>;
}
#[cfg(feature = "alloc")]
bijective_higher_ranked_type! {
pub type [][T][]: TypeName[][]
- for<'lt>
- (DynBoxedStatic<'lt, T>)
+ for<'ctx>
+ (DynBoxedStatic<T>)
where {
T: ?Sized + 'static
}
}
-#[derive(Debug)]
-pub enum BorrowedStaticValue<'ctx, T: ?Sized + 'static> {
- Ctx(&'ctx T),
- Static(&'static T),
-}
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn owned_static_has_type_name() {
+ let a = TypeNameId::of_value(&OwnedStatic(42_i32));
+ let b = TypeNameId::of_value(&OwnedStatic(123_i32));
+ let c = TypeNameId::of_value(&OwnedStatic(true));
+
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
+
+ #[test]
+ fn borrowed_static_has_type_name() {
+ let a = TypeNameId::of_value(&BorrowedStatic(&42_i32));
+ let b = TypeNameId::of_value(&BorrowedStatic(&123_i32));
+ let c = TypeNameId::of_value(&BorrowedStatic(&true));
+
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
+
+ #[test]
+ fn temp_borrowed_static_has_type_name() {
+ let a = TypeNameId::of_value(&TempBorrowedStatic(&42_i32));
+ let b = TypeNameId::of_value(&TempBorrowedStatic(&123_i32));
+ let c = TypeNameId::of_value(&TempBorrowedStatic(&true));
+
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
+
+ #[test]
+ fn borrowed_mut_static_has_type_name() {
+ let mut a = 42_i32;
+ let mut b = 123_i32;
+ let mut c = true;
+
+ let a = TypeNameId::of_value(&BorrowedMutStatic(&mut a));
+ let b = TypeNameId::of_value(&BorrowedMutStatic(&mut b));
+ let c = TypeNameId::of_value(&BorrowedMutStatic(&mut c));
-#[derive(Debug)]
-pub enum BorrowedMutStaticValue<'ctx, T: ?Sized + 'static> {
- Ctx(&'ctx mut T),
- Static(&'static mut T),
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
+
+ #[test]
+ fn temp_borrowed_mut_static_has_type_name() {
+ let mut a = 42_i32;
+ let mut b = 123_i32;
+ let mut c = true;
+
+ let a = TypeNameId::of_value(&TempBorrowedMutStatic(&mut a));
+ let b = TypeNameId::of_value(&TempBorrowedMutStatic(&mut b));
+ let c = TypeNameId::of_value(&TempBorrowedMutStatic(&mut c));
+
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn boxed_static_has_type_name() {
+ let a = TypeNameId::of_value(&BoxedStatic(Box::new(42_i32)));
+ let b = TypeNameId::of_value(&BoxedStatic(Box::new(123_i32)));
+ let c = TypeNameId::of_value(&BoxedStatic(Box::new(true)));
+
+ assert_eq!(a, b);
+ assert_ne!(a, c);
+ assert_ne!(b, c);
+ }
}
diff --git a/src/any/type_name_id.rs b/src/any/type_name_id.rs
new file mode 100644
index 0000000..5198073
--- /dev/null
+++ b/src/any/type_name_id.rs
@@ -0,0 +1,156 @@
+use core::any::TypeId;
+
+#[cfg(feature = "better_errors")]
+use core::any::type_name;
+
+use super::{TypeName, WithContextLt};
+
+/// [`TypeId`] for the [`TypeName`] family of types.
+///
+/// When the `better_errors` feature is enabled this type also stores
+/// the type name.
+#[derive(Copy, Clone)]
+pub struct TypeNameId {
+ /// Type ID of the lifetime-less higher ranked type
+ name_id: TypeId,
+
+ /// Name of the lifetime containing type for better error messages.
+ #[cfg(feature = "better_errors")]
+ name: &'static str,
+}
+
+impl TypeNameId {
+ /// Get the type ID from a [`TypeName`] higher ranked type.
+ pub fn of_type_name<T: ?Sized + TypeName::MemberType>() -> Self {
+ Self {
+ name_id: TypeId::of::<T>(),
+
+ #[cfg(feature = "better_errors")]
+ name: type_name::<WithContextLt::T<'_, '_, TypeName::T<'_, T>>>(),
+ }
+ }
+
+ /// Get the type ID from a [`TypeName::LowerType`] ([`WithContextLt`]) higher ranked type.
+ pub fn of<'ctx, T: ?Sized + TypeName::LowerType<'ctx>>() -> Self {
+ Self {
+ name_id: TypeId::of::<TypeName::HigherRanked<'ctx, T>>(),
+
+ #[cfg(feature = "better_errors")]
+ name: type_name::<WithContextLt::T<'_, '_, T>>(),
+ }
+ }
+
+ /// Get the type ID from a lower type.
+ pub fn of_lower<'a, 'ctx: 'a, T: ?Sized + WithContextLt::LowerType<'a, 'ctx>>() -> Self
+ where
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx>,
+ {
+ Self {
+ name_id: TypeId::of::<
+ TypeName::HigherRanked<'ctx, WithContextLt::HigherRanked<'a, 'ctx, T>>,
+ >(),
+
+ #[cfg(feature = "better_errors")]
+ name: type_name::<T>(),
+ }
+ }
+
+ /// Get the type ID of a lower type's value.
+ pub fn of_value<'a, 'ctx: 'a, T: ?Sized + WithContextLt::LowerType<'a, 'ctx>>(_: &T) -> Self
+ where
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx>,
+ {
+ Self::of_lower::<'a, 'ctx, T>()
+ }
+}
+
+impl core::fmt::Debug for TypeNameId {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ #[cfg(feature = "better_errors")]
+ {
+ core::fmt::Display::fmt(self.name, f)
+ }
+
+ #[cfg(not(feature = "better_errors"))]
+ {
+ core::fmt::Debug::fmt(&self.name_id, f)
+ }
+ }
+}
+
+impl PartialEq for TypeNameId {
+ fn eq(&self, other: &Self) -> bool {
+ self.name_id == other.name_id
+ }
+}
+
+impl Eq for TypeNameId {}
+
+impl PartialOrd for TypeNameId {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ self.name_id.partial_cmp(&other.name_id)
+ }
+}
+
+impl Ord for TypeNameId {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.name_id.cmp(&other.name_id)
+ }
+}
+
+impl core::hash::Hash for TypeNameId {
+ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+ self.name_id.hash(state);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use crate::bijective_higher_ranked_type;
+
+ use super::*;
+
+ #[allow(unused)]
+ struct Example<'a, 'ctx: 'a, T>(&'a &'ctx T);
+
+ bijective_higher_ranked_type! {
+ type DynExample['ctx][T]: WithContextLt['ctx][]
+ for<'a>
+ (Example<'a, 'ctx, T>)
+ where {
+ T: 'ctx
+ }
+ }
+
+ bijective_higher_ranked_type! {
+ type NameExample[][T][]: TypeName[][]
+ for<'ctx>
+ (DynExample<'ctx, T>)
+ where {
+ T: 'static
+ }
+ }
+
+ #[test]
+ fn type_name_id_is_the_same() {
+ let a = TypeNameId::of_value(&Example(&&()));
+ let b = TypeNameId::of_lower::<Example<'_, '_, ()>>();
+ let c = TypeNameId::of::<DynExample<'_, ()>>();
+ let d = TypeNameId::of_type_name::<NameExample<()>>();
+
+ assert_eq!(a, b);
+ assert_eq!(a, c);
+ assert_eq!(a, d);
+ assert_eq!(b, c);
+ assert_eq!(b, d);
+ assert_eq!(c, d);
+ }
+
+ #[test]
+ fn type_name_id_is_different() {
+ let a = TypeNameId::of::<DynExample<'_, i8>>();
+ let b = TypeNameId::of::<DynExample<'_, u8>>();
+
+ assert_ne!(a, b);
+ }
+}
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs
index a97662e..54efc96 100644
--- a/src/build/builders/debug.rs
+++ b/src/build/builders/debug.rs
@@ -3,7 +3,7 @@ use core::{any::TypeId, marker::PhantomData, ops::ControlFlow};
use crate::{
any::{
static_wrapper::{DynOwnedStatic, OwnedStatic},
- LtTypeId,
+ TypeNameId,
},
any_trait,
effect::{Effect, Future},
@@ -34,11 +34,11 @@ any_trait! {
DynValue<'ctx, DynOwnedStatic<bool>, E>,
// DynValue<'a, 'ctx, OwnedStatic<&'static [&'static str]>, E>,
DynSequence<'ctx, E>,
- ] else fallback where E: Effect<'ctx>
-}
-
-fn fallback(id: LtTypeId<'_>) {
- // println!("Unknown trait: {}", id);
+ ] else {
+ let id;
+ println!("Unknown trait: {:?}", id);
+ None
+ } where E: Effect<'ctx>
}
impl<'ctx, E: Effect<'ctx>> Visitor<E> {
diff --git a/src/hkt.rs b/src/hkt.rs
index 58539db..83a051e 100644
--- a/src/hkt.rs
+++ b/src/hkt.rs
@@ -100,6 +100,7 @@ pub use higher_ranked_type;
#[macro_export]
macro_rules! bijective_higher_ranked_trait {
{
+ $(#[$($meta:tt)*])*
$vis:vis type class $name:ident[
$($lifetimes:lifetime),*
][
@@ -112,53 +113,151 @@ macro_rules! bijective_higher_ranked_trait {
$($for_bound:tt)*
})?
} => {
+ $(#[$($meta)*])*
$vis mod $name {
#![allow(unused, non_snake_case)]
use super::*;
- pub trait LowerForLt<$lt, $($lifetimes,)* B, $($generic),*> $(: $($self_provides)*)?
- where $($($bound)*)? $($($for_bound)*)?
-
+ /// Trait for lowering a higher ranked type to a lower type.
+ ///
+ /// Do not use this trait directly instead use the [`MemberType`] trait and [`T`]
+ /// type alias.
+ ///
+ /// This acts to inject a lifetime into the higher ranked type to make it concrete.
+ pub trait LowerForLt<$lt, $($lifetimes: $lt,)* B: $lt, $($generic: $lt),*> $(: $($self_provides)*)?
+ where
+ $($($bound)*)?
+ $($($for_bound)*)?
{
- type T: ?Sized + RaiseForLt<$lt, $($lifetimes,)* B, $($generic,)* HigherRanked = Self> $(+ $($provides)+)? + $lt;
+ /// The lower type for this higher ranked type.
+ ///
+ /// The lower type must live for a minimum of the injected lifetime.
+ ///
+ /// Note this type must be raisable back to the same higher ranked type to make
+ /// this a bijective mapping.
+ type T: ?Sized + RaiseForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic,)*
+ HigherRanked = Self
+ > $(+ $($provides)+)? + $lt;
}
- pub trait RaiseForLt<$lt, $($lifetimes,)* B, $($generic),*>
- where $($($bound)*)? $($($for_bound)*)?
-
+ /// Trait for raising a lower type to it's higher ranked form.
+ ///
+ /// Do not use this trait directly instead use the [`LowerType`] trait and [`HigherRanked`]
+ /// type alias.
+ ///
+ /// this acts to remove a lifetime from the lower type.
+ pub trait RaiseForLt<$lt, $($lifetimes: $lt,)* B: $lt, $($generic: $lt),*>
+ where
+ $($($bound)*)?
+ $($($for_bound)*)?
{
- type HigherRanked: ?Sized + LowerForLt<$lt, $($lifetimes,)* B, $($generic,)* T = Self> + $($lifetimes +)*;
+ /// The higher ranked type for this lower type.
+ ///
+ /// Note this type must be lowerable back to the same lower type to make
+ /// this a bijective mapping.
+ type HigherRanked: ?Sized + LowerForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic,)*
+ T = Self
+ > $(+ $lifetimes)*;
}
- pub trait Trait<$($lifetimes,)* $($generic),*>:
- for<$lt> LowerForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*>
+ /// Trait for higher ranked types of this form.
+ ///
+ /// A higher ranked type can have a lifetime injected to form a lower type.
+ /// To perform this operation use the [`T`] type alias.
+ ///
+ /// This is basically a trait alias for the bound `for<'a> LowerForLt<'a, ...>`.
+ pub trait MemberType<$($lifetimes,)* $($generic),*>:
+ for<$lt> LowerForLt<
+ $lt,
+ $($lifetimes,)*
+ // Use a implied bound to make sure the lifetime from the for syntax is
+ // correctly bounded.
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ >
where
$($($bound)*)?
{}
- impl<$($lifetimes,)* __: ?Sized, $($generic),*> Trait<$($lifetimes,)* $($generic),*> for __
+ // Impl the higher ranked trait for all higher ranked types with the ability to lower.
+ impl<
+ $($lifetimes,)*
+ __: ?Sized,
+ $($generic),*
+ > MemberType<$($lifetimes,)* $($generic),*> for __
where
- __: for<$lt> LowerForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*>,
+ __: for<$lt> LowerForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ >,
$($($bound)*)?
{}
- pub type T<$lt, $($lifetimes,)* __, $($generic),*> = <__ as LowerForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*>>::T;
-
- pub trait Member<$lt, $($lifetimes,)* $($generic),*>: RaiseForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*> $(+ $($provides)+)?
+ /// Inject a lifetime into a higher ranked type to form its lower type.
+ pub type T<$lt, $($lifetimes,)* __, $($generic),*> =
+ <__ as LowerForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ >>::T;
+
+ /// Trait for lower types with a higher ranked form.
+ ///
+ /// A lower type can have a lifetime removed to form a higher ranked type.
+ /// To perform this operation use the [`HigherRanked`] type alias.
+ ///
+ /// This is basically a trait alias for the bound `RaiseForLt<'a, ...>`.
+ pub trait LowerType<
+ $lt,
+ $($lifetimes: $lt,)*
+ $($generic: $lt),*
+ >: RaiseForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ > $(+ $($provides)+)?
where
- ($(&$lifetimes (),)*): $lt,
$($($bound)*)?
{}
- impl<$lt, $($lifetimes,)* __: ?Sized, $($generic),*> Member<$lt, $($lifetimes,)* $($generic),*> for __
+ // Impl the lower type trait for all lower types with the ability to raise.
+ impl<
+ $lt,
+ $($lifetimes: $lt,)*
+ __: ?Sized,
+ $($generic: $lt),*
+ > LowerType<$lt, $($lifetimes,)* $($generic),*> for __
where
- __: RaiseForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*> $(+ $($provides)+)?,
- ($(&$lifetimes (),)*): $lt,
+ __: RaiseForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ > $(+ $($provides)+)?,
$($($bound)*)?
{}
- pub type HigherRanked<$lt, $($lifetimes,)* __, $($generic),*> = <__ as RaiseForLt<$lt, $($lifetimes,)* &$lt ($(&$lifetimes (),)* $($generic),*), $($generic),*>>::HigherRanked;
+ /// Remove a lifetime into a lower type to form its higher ranked type.
+ pub type HigherRanked<$lt, $($lifetimes,)* __, $($generic),*> =
+ <__ as RaiseForLt<
+ $lt,
+ $($lifetimes,)*
+ &$lt ($(&$lifetimes (),)* $($generic),*),
+ $($generic),*
+ >>::HigherRanked;
}
};
}
@@ -171,6 +270,7 @@ pub use bijective_higher_ranked_trait;
#[macro_export]
macro_rules! bijective_higher_ranked_type {
{
+ $(#[$($meta:tt)*])*
$vis:vis type $name:ident[
$($ctx:lifetime),*
][
@@ -183,6 +283,7 @@ macro_rules! bijective_higher_ranked_type {
($higher_ranked_type:ty)
$(where {$($bound:tt)*})?
} => {
+ $(#[$($meta)*])*
$vis struct $name<
$($type_class_lifetime,)*
$($generic: ?Sized,)*
@@ -305,6 +406,7 @@ macro_rules! bijective_higher_ranked_type {
};
};
{
+ $(#[$($meta:tt)*])*
$vis:vis type $name:ident[
$($ctx:lifetime),*
][
@@ -317,6 +419,7 @@ macro_rules! bijective_higher_ranked_type {
$(where {$($bound:tt)*})?
} => {
$crate::hkt::bijective_higher_ranked_type! {
+ $(#[$($meta)*])*
$vis type $name[
$($ctx),*
][
diff --git a/src/mock/builder.rs b/src/mock/builder.rs
index 31c1623..9fef358 100644
--- a/src/mock/builder.rs
+++ b/src/mock/builder.rs
@@ -1,7 +1,7 @@
use mockall::mock;
use crate::{
- any::{AnyTrait, IndirectLtAny, LtTypeId, Mut, Ref},
+ any::{indirect, AnyTrait, AnyTraitObject, TypeNameId},
effect::{Effect, Future},
mock::{ContextLock, StaticTypeMap},
protocol::Visitor,
@@ -12,15 +12,13 @@ use self::__mock_MockBuilder::__from_seed::Context;
use super::ContextGuard;
-use crate::any::ForAnyTypeId;
-
mock! {
pub Builder<Seed: 'static, Value: 'static, Error: 'static> {
pub fn from_seed(seed: Seed) -> Self;
pub fn build(self) -> Result<Value, Error>;
- pub fn traits(&self, id: ForAnyTypeId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
- pub fn traits_mut(&mut self, id: ForAnyTypeId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
+ pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
+ pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
}
}
@@ -73,26 +71,24 @@ impl<'ctx, Seed: Send, Value: Send, Error: Send, E: Effect<'ctx>> Builder<'ctx,
impl<'ctx, Seed, Value, Error> AnyTrait<'ctx> for MockBuilder<Seed, Value, Error> {
#[track_caller]
- fn upcast_to_id<'a>(&'a self, id: LtTypeId<'ctx>) -> Option<IndirectLtAny<'a, 'ctx, Ref>>
+ fn upcast_to_id<'a>(&'a self, id: TypeNameId) -> Option<AnyTraitObject<'a, 'ctx, indirect::Ref>>
where
'ctx: 'a,
{
// Find the first trait handler that wants to upcast.
- self.traits(id.as_type_id())
- .as_ref()
- .and_then(|t| t.upcast_to_id(id))
+ self.traits(id).as_ref().and_then(|t| t.upcast_to_id(id))
}
#[track_caller]
- fn upcast_to_id_mut<'a: 'b, 'b>(
+ fn upcast_to_id_mut<'a>(
&'a mut self,
- id: LtTypeId<'ctx>,
- ) -> Option<IndirectLtAny<'b, 'ctx, Mut>>
+ id: TypeNameId,
+ ) -> Option<AnyTraitObject<'a, 'ctx, indirect::Mut>>
where
'ctx: 'a,
{
// Find the first trait handler that wants to upcast.
- self.traits_mut(id.as_type_id())
+ self.traits_mut(id)
.as_mut()
.and_then(|t| t.upcast_to_id_mut(id))
}
diff --git a/src/mock/protocol/value.rs b/src/mock/protocol/value.rs
index 99ba045..eca11ee 100644
--- a/src/mock/protocol/value.rs
+++ b/src/mock/protocol/value.rs
@@ -1,7 +1,7 @@
use mockall::mock;
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
any_trait,
effect::{Effect, Future},
protocol::visitor::value::{DynValue, Value},
@@ -9,11 +9,11 @@ use crate::{
};
mock! {
- pub ValueVisitor<T: for<'ctx> MaybeSized::Trait<'ctx>, E>
+ pub ValueVisitor<T: for<'ctx> WithContextLt::MemberType<'ctx>, E>
where
- for<'a, 'ctx> MaybeSized::T<'a, 'ctx, T>: Sized
+ for<'a, 'ctx> WithContextLt::T<'a, 'ctx, T>: Sized
{
- pub fn visit<'a, 'ctx>(&'a mut self, value: MaybeSized::T<'a, 'ctx, T>) -> Flow;
+ pub fn visit<'a, 'ctx>(&'a mut self, value: WithContextLt::T<'a, 'ctx, T>) -> Flow;
}
}
@@ -21,18 +21,18 @@ any_trait! {
impl['ctx, T, E] MockValueVisitor<T, E> = [
DynValue<'ctx, T, E>
] where
- T: for<'lt> TypeName::Member<'lt> + 'ctx,
- for<'a, 'lt> MaybeSized::T<'a, 'lt, T>: Sized,
+ T: for<'lt> TypeName::LowerType<'lt> + 'ctx,
+ for<'a, 'lt> WithContextLt::T<'a, 'lt, T>: Sized,
E: Effect<'ctx>,
}
-impl<'ctx, T: for<'lt> MaybeSized::Trait<'lt>, E: Effect<'ctx>> Value<'ctx, T, E>
+impl<'ctx, T: for<'lt> WithContextLt::MemberType<'lt>, E: Effect<'ctx>> Value<'ctx, T, E>
for MockValueVisitor<T, E>
where
- for<'a, 'lt> MaybeSized::T<'a, 'lt, T>: Sized,
+ for<'a, 'lt> WithContextLt::T<'a, 'lt, T>: Sized,
{
#[track_caller]
- fn visit<'a>(&'a mut self, value: MaybeSized::T<'a, 'ctx, T>) -> Future<'a, 'ctx, Flow, E> {
+ fn visit<'a>(&'a mut self, value: WithContextLt::T<'a, 'ctx, T>) -> Future<'a, 'ctx, Flow, E> {
E::ready(self.visit(value))
}
}
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs
index 4e1b307..a3a9d65 100644
--- a/src/protocol/visitor/recoverable.rs
+++ b/src/protocol/visitor/recoverable.rs
@@ -1,5 +1,5 @@
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
higher_ranked_type,
@@ -18,7 +18,7 @@ pub trait Recoverable<'ctx, E: Effect<'ctx>> {
}
bijective_higher_ranked_type! {
- pub type DynRecoverable['ctx][E]: MaybeSized['ctx][]
+ pub type DynRecoverable['ctx][E]: WithContextLt['ctx][]
for<'a>
(dyn Recoverable<'ctx, E> + Send + 'a)
where {
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index aa5f8ee..123e187 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,5 +1,5 @@
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
protocol::{Visitor, Walker},
@@ -16,7 +16,7 @@ pub trait RequestHint<'ctx, E: Effect<'ctx>> {
}
bijective_higher_ranked_type! {
- pub type DynRequestHint['ctx][E]: MaybeSized['ctx][]
+ pub type DynRequestHint['ctx][E]: WithContextLt['ctx][]
for<'a>
(dyn RequestHint<'ctx, E> + Send + 'a)
where {
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index 736a006..88fd248 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -1,5 +1,5 @@
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
higher_ranked_type,
@@ -15,7 +15,7 @@ pub trait Sequence<'ctx, E: Effect<'ctx>> {
}
bijective_higher_ranked_type! {
- pub type DynSequence['ctx][E]: MaybeSized['ctx][]
+ pub type DynSequence['ctx][E]: WithContextLt['ctx][]
for<'a>
(dyn Sequence<'ctx, E> + Send + 'a)
where {
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index b20454a..0bd5750 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -1,5 +1,5 @@
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
higher_ranked_type,
@@ -48,7 +48,7 @@ pub trait Tag<'ctx, K: TagKind, E: Effect<'ctx>> {
}
bijective_higher_ranked_type! {
- pub type DynTag['ctx][K, E]: MaybeSized['ctx][]
+ pub type DynTag['ctx][K, E]: WithContextLt['ctx][]
for<'a>
(dyn Tag<'ctx, K, E> + Send + 'a)
where {
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index 08f06d4..419964b 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -3,7 +3,7 @@
//! In some sense, this is the most basic protocol.
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
higher_ranked_type,
@@ -17,7 +17,7 @@ use super::{recoverable::Recoverable, Status};
/// Trait object for the [`Value`] protocol.
///
/// Types implementing the [`Value`] protocol will implement this trait.
-pub trait Value<'ctx, T: MaybeSized::Trait<'ctx>, E: Effect<'ctx>> {
+pub trait Value<'ctx, T: WithContextLt::MemberType<'ctx>, E: Effect<'ctx>> {
/// Visit a value of type `T`.
///
/// Use this to give a value to a visitor. Its expected that a walker
@@ -27,16 +27,16 @@ pub trait Value<'ctx, T: MaybeSized::Trait<'ctx>, E: Effect<'ctx>> {
/// If a [`ControlFlow::Break`] is returned then the walker
/// should stop walking as soon as possible as there has likely been
/// and error.
- fn visit<'a>(&'a mut self, value: MaybeSized::T<'a, 'ctx, T>) -> Future<'a, 'ctx, Flow, E>;
+ fn visit<'a>(&'a mut self, value: WithContextLt::T<'a, 'ctx, T>) -> Future<'a, 'ctx, Flow, E>;
}
bijective_higher_ranked_type! {
- pub type DynValue['ctx][T, E][]: MaybeSized['ctx][]
+ pub type DynValue['ctx][T, E][]: WithContextLt['ctx][]
for<'a>
(dyn Value<'ctx, T, E> + Send + 'a)
where {
E: Effect<'ctx>,
- T: ?Sized + MaybeSized::Trait<'ctx> + 'ctx
+ T: ?Sized + WithContextLt::MemberType<'ctx> + 'ctx
}
}
@@ -62,15 +62,15 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for DynValue<'ctx, T, E> {
type Hint = ();
}
-pub fn visit_value<'a, 'ctx, T: MaybeSized::Member<'a, 'ctx> + 'ctx, E: Effect<'ctx>>(
+pub fn visit_value<'a, 'ctx, T: WithContextLt::LowerType<'a, 'ctx> + 'ctx, E: Effect<'ctx>>(
visitor: Visitor<'a, 'ctx>,
value: T,
) -> Future<'a, 'ctx, Status, E>
where
- MaybeSized::HigherRanked<'a, 'ctx, T>: TypeName::Member<'ctx> + Sized,
+ WithContextLt::HigherRanked<'a, 'ctx, T>: TypeName::LowerType<'ctx> + Sized,
{
if let Some(object) =
- visitor.upcast_mut::<DynValue<'ctx, MaybeSized::HigherRanked<'a, 'ctx, T>, E>>()
+ visitor.upcast_mut::<DynValue<'ctx, WithContextLt::HigherRanked<'a, 'ctx, T>, E>>()
{
// Allow the visitor to give a hint if it wants.
E::map(object.visit(value), |flow| match flow {
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 85184de..e7d41c6 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -5,7 +5,7 @@
//! to the walker about what it is expecting.
use crate::{
- any::{MaybeSized, TypeName},
+ any::{TypeName, WithContextLt},
bijective_higher_ranked_type,
effect::{Effect, Future},
hkt::AnySend,
@@ -48,12 +48,12 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>, E: Effect<'ctx>> {
}
bijective_higher_ranked_type! {
- pub type DynHint['ctx][Protocol, E]: MaybeSized['ctx][]
+ pub type DynHint['ctx][Protocol, E]: WithContextLt['ctx][]
for<'a>
(dyn Hint<'ctx, Protocol, E> + Send + 'a)
where {
E: Effect<'ctx>,
- Protocol: ?Sized + MaybeSized::Trait<'ctx> + 'ctx,
+ Protocol: ?Sized + WithContextLt::MemberType<'ctx> + 'ctx,
}
}
@@ -85,7 +85,7 @@ mod test {
struct Y;
bijective_higher_ranked_type! {
- type DynY['ctx][]: MaybeSized['ctx][] for<'a> (Y)
+ type DynY['ctx][]: WithContextLt['ctx][] for<'a> (Y)
}
bijective_higher_ranked_type! {
@@ -121,9 +121,10 @@ mod test {
let mut z = 42;
let mut x = X(&mut z);
- let y: &mut MaybeSized::T<'_, '_, DynHint<'_, DynY<'_>, Blocking>> = &mut x;
+ let y: &mut WithContextLt::T<'_, '_, DynHint<'_, DynY<'_>, Blocking>> = &mut x;
- fn id<'a, 'ctx, T: ?Sized + TypeName::Member<'ctx>>(_x: &MaybeSized::T<'a, 'ctx, T>) {}
+ fn id<'a, 'ctx, T: ?Sized + TypeName::LowerType<'ctx>>(_x: &WithContextLt::T<'a, 'ctx, T>) {
+ }
id::<DynHint<'_, DynY<'_>, Blocking>>(y);
let x = Spin::block_on(y.known(&()));
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index cbcb5c0..e78094e 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -667,7 +667,7 @@ mod test {
use crate::{
any::{
static_wrapper::{DynOwnedStatic, OwnedStatic},
- LtTypeId,
+ TypeNameId,
},
effect::{BlockOn as _, Blocking, Spin},
mock::{
@@ -732,10 +732,9 @@ mod test {
builder
.expect_traits_mut()
.once()
- .with(eq(LtTypeId::of::<
+ .with(eq(TypeNameId::of::<
DynTag<'static, TagConst<{ TAG_STRUCT.to_int() }>, Blocking>,
- >()
- .as_type_id()))
+ >()))
.in_sequence(&mut seq)
.return_var(Some(Box::new({
let mut mock = MockTagVisitor::<TagConst<{ TAG_STRUCT.to_int() }>, Blocking>::new();
@@ -756,10 +755,9 @@ mod test {
builder
.expect_traits_mut()
.once()
- .with(eq(LtTypeId::of::<
+ .with(eq(TypeNameId::of::<
DynTag<'static, TagConst<{ TAG_TYPE_NAME.to_int() }>, Blocking>,
- >()
- .as_type_id()))
+ >()))
.in_sequence(&mut seq)
.return_var(Some(Box::new({
let mut mock =
@@ -771,10 +769,9 @@ mod test {
builder
.expect_traits_mut()
.once()
- .with(eq(LtTypeId::of::<
+ .with(eq(TypeNameId::of::<
DynValue<'static, DynOwnedStatic<&'static str>, Blocking>,
- >()
- .as_type_id()))
+ >()))
.return_var(Some(Box::new({
let mut mock =
MockValueVisitor::<DynOwnedStatic<&'static str>, Blocking>::new();