cleaned up the any module
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/any.rs | 585 | ||||
| -rw-r--r-- | src/any/indirect.rs | 237 | ||||
| -rw-r--r-- | src/any/static_wrapper.rs | 189 | ||||
| -rw-r--r-- | src/any/type_name_id.rs | 156 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 12 | ||||
| -rw-r--r-- | src/hkt.rs | 143 | ||||
| -rw-r--r-- | src/mock/builder.rs | 22 | ||||
| -rw-r--r-- | src/mock/protocol/value.rs | 18 | ||||
| -rw-r--r-- | src/protocol/visitor/recoverable.rs | 4 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 4 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 4 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 4 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 16 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 13 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 17 |
16 files changed, 925 insertions, 500 deletions
@@ -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" @@ -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> { @@ -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(); |