| -rw-r--r-- | src/any.rs | 53 | ||||
| -rw-r--r-- | src/any/static_wrapper.rs | 28 | ||||
| -rw-r--r-- | src/any/type_name_id.rs | 15 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 5 | ||||
| -rw-r--r-- | src/effect.rs | 42 | ||||
| -rw-r--r-- | src/hkt.rs | 24 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 2 | ||||
| -rw-r--r-- | src/protocol/visitor/recoverable.rs | 23 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 10 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 22 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 23 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 49 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 27 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 101 | ||||
| -rw-r--r-- | src/walk/walkers/core/tag.rs | 2 | ||||
| -rw-r--r-- | src/walk/walkers/core/value.rs | 6 | ||||
| -rw-r--r-- | tests/common/protocol.rs | 1 | ||||
| -rw-r--r-- | tests/common/protocol/hint.rs | 46 | ||||
| -rw-r--r-- | tests/common/protocol/tag.rs | 2 | ||||
| -rw-r--r-- | tests/common/protocol/visitor.rs | 13 | ||||
| -rw-r--r-- | tests/protocol_visitor_value.rs | 270 |
21 files changed, 579 insertions, 185 deletions
@@ -6,7 +6,10 @@ pub mod indirect; mod static_wrapper; mod type_name_id; -use crate::{higher_ranked_trait, higher_ranked_type, hkt::{Invariant, Marker}}; +use crate::{ + higher_ranked_trait, higher_ranked_type, + hkt::{Invariant, Marker}, +}; use core::marker::PhantomData; pub use static_wrapper::*; @@ -19,11 +22,11 @@ higher_ranked_trait! { pub type class TypeName for<'a, 'ctx> { type Bound = &'a &'ctx (); - type T: { } where { + type T: { Send + Sync + 'a } where { 'ctx: 'a }; - type HigherRanked: { 'static }; + type HigherRanked: { Send + Sync + 'static }; } } @@ -31,14 +34,14 @@ pub struct RefHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { - impl['a, 'ctx, T] type T['a, 'ctx] for RefHrt<T> = - &'a TypeName::T<'a, 'ctx, T> + impl['a, 'ctx, T] type T['a, 'ctx] for RefHrt<T> = + &'a TypeName::T<'a, 'ctx, T> where { T: ?Sized + TypeName::LowerForLt<'a, 'ctx, TypeName::Bound<'a, 'ctx>>, TypeName::T<'a, 'ctx, T>: 'a }; - impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for &'a T = + impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for &'a T = RefHrt<TypeName::HigherRanked<'a, 'ctx, T>> where { T: ?Sized + TypeName::LowerType<'a, 'ctx> @@ -50,14 +53,14 @@ pub struct MutHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { - impl['a, 'ctx, T] type T['a, 'ctx] for MutHrt<T> = - &'a mut TypeName::T<'a, 'ctx, T> + impl['a, 'ctx, T] type T['a, 'ctx] for MutHrt<T> = + &'a mut TypeName::T<'a, 'ctx, T> where { T: ?Sized + TypeName::LowerForLt<'a, 'ctx, TypeName::Bound<'a, 'ctx>>, TypeName::T<'a, 'ctx, T>: 'a }; - impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for &'a mut T = + impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for &'a mut T = MutHrt<TypeName::HigherRanked<'a, 'ctx, T>> where { T: ?Sized + TypeName::LowerType<'a, 'ctx> @@ -68,13 +71,13 @@ higher_ranked_type! { #[cfg(feature = "alloc")] higher_ranked_type! { impl TypeName { - impl['a, 'ctx, T] type T['a, 'ctx] for Box<T> = + impl['a, 'ctx, T] type T['a, 'ctx] for Box<T> = Box<TypeName::T<'a, 'ctx, T>> where { T: ?Sized + TypeName::LowerForLt<'a, 'ctx, TypeName::Bound<'a, 'ctx>>, }; - impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for Box<T> = + impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for Box<T> = Box<TypeName::HigherRanked<'a, 'ctx, T>> where { T: ?Sized + TypeName::LowerType<'a, 'ctx> @@ -116,9 +119,9 @@ higher_ranked_type! { /// higher_ranked_type! { /// impl TypeName { /// impl['a, 'ctx] type T['a, 'ctx] for DynToNum = -/// dyn ToNum + 'a; +/// dyn ToNum + Send + Sync + 'a; /// -/// impl['a, 'ctx] type HigherRanked['a, 'ctx] for dyn ToNum + 'a = +/// impl['a, 'ctx] type HigherRanked['a, 'ctx] for dyn ToNum + Send + Sync + 'a = /// DynToNum; /// } /// } @@ -344,9 +347,7 @@ impl<'a, 'ctx, I: Indirect<'a>> AnyTraitObject<'a, 'ctx, I> { /// /// If the type of the stored value is different, then `self` is /// returned as is. - pub fn downcast<T: ?Sized + TypeName::LowerType<'a, 'ctx>>( - self, - ) -> Result<I::ForT<T>, Self> { + pub fn downcast<T: ?Sized + TypeName::LowerType<'a, 'ctx>>(self) -> Result<I::ForT<T>, Self> { 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. @@ -383,9 +384,9 @@ mod test { higher_ranked_type! { impl TypeName { impl['a, 'ctx] type T['a, 'ctx] for DynZ = - dyn Z<'ctx> + 'a; + dyn Z<'ctx> + Send + Sync + 'a; - impl['a, 'ctx] type HigherRanked['a, 'ctx] for dyn Z<'ctx> + 'a = + impl['a, 'ctx] type HigherRanked['a, 'ctx] for dyn Z<'ctx> + Send + Sync + 'a = DynZ; } } @@ -406,9 +407,7 @@ mod test { let z = 42; let x = X(&z); - let y = (&x as &(dyn AnyTrait<'_> + Send)) - .upcast::<DynZ>() - .unwrap(); + let y = (&x as &(dyn AnyTrait<'_> + Send)).upcast::<DynZ>().unwrap(); assert_eq!(y.get(), 42); } @@ -428,11 +427,7 @@ mod test { // This proves that the bijective type names are really bijective. fn _is_bijective_raise<'a, 'ctx: 'a, T>( - x: &TypeName::T< - 'a, - 'ctx, - TypeName::HigherRanked<'a, 'ctx, T>, - >, + x: &TypeName::T<'a, 'ctx, TypeName::HigherRanked<'a, 'ctx, T>>, ) where T: TypeName::LowerType<'a, 'ctx>, { @@ -442,11 +437,7 @@ mod test { // This proves that the bijective type names are really bijective. fn _is_bijective_lower<'a, 'ctx: 'a, U>( - x: &TypeName::HigherRanked< - 'a, - 'ctx, - TypeName::T<'a, 'ctx, U>, - >, + x: &TypeName::HigherRanked<'a, 'ctx, TypeName::T<'a, 'ctx, U>>, ) where U: TypeName::MemberType, { diff --git a/src/any/static_wrapper.rs b/src/any/static_wrapper.rs index 58d101b..3d9d057 100644 --- a/src/any/static_wrapper.rs +++ b/src/any/static_wrapper.rs @@ -12,16 +12,17 @@ pub struct OwnedStatic<T: ?Sized>(pub T); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for OwnedStatic<T> = OwnedStatic<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for OwnedStatic<T> = OwnedStatic<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } /// Borrowed static `T` for `'ctx`. +#[derive(PartialEq, Clone, Copy, Debug)] #[repr(transparent)] pub struct BorrowedStatic<'ctx, T: ?Sized>(pub &'ctx T); @@ -30,16 +31,17 @@ pub struct BorrowedStaticHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for BorrowedStaticHrt<T> = BorrowedStatic<'ctx, T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for BorrowedStatic<'ctx, T> = BorrowedStaticHrt<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } /// Borrowed static `T` for `'a`. +#[derive(PartialEq, Clone, Copy, Debug)] #[repr(transparent)] pub struct TempBorrowedStatic<'a, T: ?Sized>(pub &'a T); @@ -48,16 +50,17 @@ pub struct TempBorrowedStaticHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for TempBorrowedStaticHrt<T> = TempBorrowedStatic<'a, T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for TempBorrowedStatic<'a, T> = TempBorrowedStaticHrt<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } /// Mutably borrowed static `T` for `'ctx`. +#[derive(PartialEq, Debug)] #[repr(transparent)] pub struct BorrowedMutStatic<'ctx, T: ?Sized>(pub &'ctx mut T); @@ -66,16 +69,17 @@ pub struct BorrowedMutStaticHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for BorrowedMutStaticHrt<T> = BorrowedMutStatic<'ctx, T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for BorrowedMutStatic<'ctx, T> = BorrowedMutStaticHrt<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } /// Mutably borrowed static `T` for `'a`. +#[derive(PartialEq, Debug)] #[repr(transparent)] pub struct TempBorrowedMutStatic<'a, T: ?Sized>(pub &'a mut T); @@ -84,11 +88,11 @@ pub struct TempBorrowedMutStaticHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for TempBorrowedMutStaticHrt<T> = TempBorrowedMutStatic<'a, T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for TempBorrowedMutStatic<'a, T> = TempBorrowedMutStaticHrt<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } @@ -102,11 +106,11 @@ pub struct BoxedStatic<T: ?Sized>(pub Box<T>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, T] type T['a, 'ctx] for BoxedStatic<T> = BoxedStatic<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for BoxedStatic<T> = BoxedStatic<T> where { - T: ?Sized + 'static + T: ?Sized + Send + Sync + 'static }; } } diff --git a/src/any/type_name_id.rs b/src/any/type_name_id.rs index 5776063..1e47f12 100644 --- a/src/any/type_name_id.rs +++ b/src/any/type_name_id.rs @@ -33,9 +33,7 @@ impl TypeNameId { /// Get the type ID from a lower type. pub fn of_lower<'a, 'ctx: 'a, T: ?Sized + TypeName::LowerType<'a, 'ctx>>() -> Self { Self { - name_id: TypeId::of::< - TypeName::HigherRanked<'a, 'ctx, T>, - >(), + name_id: TypeId::of::<TypeName::HigherRanked<'a, 'ctx, T>>(), #[cfg(feature = "better_errors")] name: type_name::<T>(), @@ -46,6 +44,13 @@ impl TypeNameId { pub fn of_value<'a, 'ctx: 'a, T: ?Sized + TypeName::LowerType<'a, 'ctx>>(_: &T) -> Self { Self::of_lower::<'a, 'ctx, T>() } + + /// Converts the type name ID to a normal [`TypeId`]. + /// + /// This is the [`TypeId`] of the `T` passed to [`Self::of`]. + pub fn into_type_id(self) -> TypeId { + self.name_id + } } impl core::fmt::Debug for TypeNameId { @@ -104,13 +109,13 @@ mod test { impl['a, 'ctx, T] type T['a, 'ctx] for ExampleHrt<T> = Example<'a, 'ctx, T> where { - T: 'static + T: 'static + Send + Sync }; impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for Example<'a, 'ctx, T> = ExampleHrt<T> where { - T: 'static + T: 'static + Send + Sync }; } } diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs index f1d8d1f..b7331a1 100644 --- a/src/build/builders/debug.rs +++ b/src/build/builders/debug.rs @@ -4,13 +4,14 @@ use crate::{ any::OwnedStatic, any_trait, effect::{Effect, Future}, - protocol::{visitor::SequenceProto, Walker}, protocol::{ self, visitor::{ - DynSequenceScope, RequestHint, RequestHintProto, Sequence, Tag, TagDyn, TagProto, Value, ValueProto, VisitResult + DynSequenceScope, RequestHint, RequestHintProto, Sequence, Tag, TagDyn, TagProto, + Value, ValueProto, VisitResult, }, }, + protocol::{visitor::SequenceProto, Walker}, DynWalker, Flow, }; diff --git a/src/effect.rs b/src/effect.rs index 9c72977..1d10cbc 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -22,7 +22,7 @@ higher_ranked_trait! { } /// Trait for effects. -pub trait Effect: Send + 'static { +pub trait Effect: Send + Sync + 'static { type Future<T: Send>: SendFuture::MemberType<T>; fn wrap<'a, F>(future: F) -> SendFuture::T<'a, F::Output, Self::Future<F::Output>> @@ -106,16 +106,36 @@ pub fn noop() -> Waker { unsafe { Waker::from_raw(RAW) } } +pub struct Ready<Output> { + pub value: Option<Output>, +} + +impl<Output> Ready<Output> { + pub fn into_innter(self) -> Output { + self.value.expect("`into_inner` called after completion") + } +} + +impl<Output> Unpin for Ready<Output> {} + +impl<Output> core::future::Future for Ready<Output> { + type Output = Output; + + fn poll(mut self: core::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(self.value.take().expect("`Ready` polled after completion")) + } +} + higher_ranked_type! { impl SendFuture { - impl['a, Output] type T['a, Output] for core::future::Ready<Output> = - core::future::Ready<Output> + impl['a, Output] type T['a, Output] for Ready<Output> = + Ready<Output> where { Output: Send }; - impl['a, Output] type HigherRanked['a, Output] for core::future::Ready<Output> = - core::future::Ready<Output> + impl['a, Output] type HigherRanked['a, Output] for Ready<Output> = + Ready<Output> where { Output: Send }; @@ -123,18 +143,20 @@ higher_ranked_type! { } impl<B: BlockOn> Effect for Blocking<B> { - type Future<T: Send> = core::future::Ready<T>; + type Future<T: Send> = Ready<T>; fn wrap<'a, F>(future: F) -> SendFuture::T<'a, F::Output, Self::Future<F::Output>> where F: core::future::Future + Send + 'a, <F as core::future::Future>::Output: Send, { - core::future::ready(B::block_on(future)) + Ready { + value: Some(B::block_on(future)), + } } fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, T, Self::Future<T>> { - core::future::ready(value) + Ready { value: Some(value) } } fn map<'a, T, U, F>( @@ -147,7 +169,9 @@ impl<B: BlockOn> Effect for Blocking<B> { F: FnOnce(T) -> U + Send + 'a, { let value = B::block_on(future); - core::future::ready(func(value)) + Ready { + value: Some(func(value)), + } } } @@ -28,20 +28,20 @@ pub struct Invariant<'a>(PhantomData<fn(&'a ()) -> &'a ()>); #[repr(transparent)] pub struct Marker<T: ?Sized>(PhantomData<fn() -> *const T>); -impl<T> Copy for Marker<T> {} -impl<T> Clone for Marker<T> { +impl<T: ?Sized> Copy for Marker<T> {} +impl<T: ?Sized> Clone for Marker<T> { fn clone(&self) -> Self { *self } } -impl<T> core::fmt::Debug for Marker<T> { +impl<T: ?Sized> core::fmt::Debug for Marker<T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Marker").finish() } } -impl<T> Default for Marker<T> { +impl<T: ?Sized> Default for Marker<T> { fn default() -> Self { Self(PhantomData) } @@ -70,7 +70,7 @@ macro_rules! higher_ranked_trait { type T: RaiseForLt<$($lt,)+ $($($generic)*,)? B, HigherRanked = Self> + ?Sized + $($lower)*; } - pub trait RaiseForLt<$($lt,)+ $($($generic)*,)? B> + pub trait RaiseForLt<$($lt,)+ $($($generic)*,)? B> where $($($lower_where)*)? $($($higher_where)*)? @@ -80,35 +80,35 @@ macro_rules! higher_ranked_trait { pub type Bound<$($lt,)+ $($($generic)*)?> = $bound; - pub trait MemberType$(<$($generic)*>)?: + pub trait MemberType$(<$($generic)*>)?: for<$($lt,)+> LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($higher)* $(where $($higher_where)*)? {} - impl<$($($generic)*,)? __: ?Sized> MemberType$(<$($generic)*>)? for __ + impl<$($($generic)*,)? __: ?Sized> MemberType$(<$($generic)*>)? for __ where __: for<$($lt,)+> LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($higher)? $($($higher_where)*)? {} - pub trait LowerType<$($lt,)+ $($($generic)*)?>: + pub trait LowerType<$($lt,)+ $($($generic)*)?>: RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($lower)* where $($($lower_where)*)? $($($higher_where)*)? {} - impl<$($lt,)+ $($($generic)*,)? __: ?Sized> LowerType<$($lt,)+ $($($generic)*)?> for __ + impl<$($lt,)+ $($($generic)*,)? __: ?Sized> LowerType<$($lt,)+ $($($generic)*)?> for __ where __: RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($lower)*, $($($lower_where)*)? $($($higher_where)*)? {} - pub type T<$($lt,)+ $($($generic)*,)? __> = + pub type T<$($lt,)+ $($($generic)*,)? __> = <__ as LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>>>::T; - pub type HigherRanked<$($lt,)+ $($($generic)*,)? __> = + pub type HigherRanked<$($lt,)+ $($($generic)*,)? __> = <__ as RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>>>::HigherRanked; } } @@ -120,7 +120,7 @@ pub use higher_ranked_trait; macro_rules! higher_ranked_type { { impl $higher_trait:ident { - impl$([$($lower_generic:tt)*])? type T[$($lower_forward:tt)*] for $lower_higher:ty = + impl$([$($lower_generic:tt)*])? type T[$($lower_forward:tt)*] for $lower_higher:ty = $lower:ty $(where {$($lower_where:tt)*})?; diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index fd8d8cd..ecb48d1 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -12,7 +12,7 @@ pub use sequence::*; pub use tag::*; pub use value::*; -#[derive(Debug)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum VisitResult<S> { /// The protocol was not used. /// diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs index af3e494..4c9c604 100644 --- a/src/protocol/visitor/recoverable.rs +++ b/src/protocol/visitor/recoverable.rs @@ -1,5 +1,13 @@ use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_type, hkt::Marker, protocol::{walker::hint::{HintKnown, HintMeta}, Visitor}, Status + any::TypeName, + effect::{Effect, Future}, + higher_ranked_type, + hkt::Marker, + protocol::{ + walker::hint::{HintKnown, HintMeta}, + Visitor, + }, + Status, }; use super::VisitResult; @@ -16,12 +24,12 @@ pub struct RecoverableProto<E: Effect>(Marker<E>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, E] type T['a, 'ctx] for RecoverableProto<E> = - dyn Recoverable<'ctx, E> + Send + 'a + dyn Recoverable<'ctx, E> + Send + Sync + 'a where { E: Effect }; - impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn Recoverable<'ctx, E> + Send + 'a = + impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn Recoverable<'ctx, E> + Send + Sync + 'a = RecoverableProto<E> where { E: Effect @@ -33,21 +41,22 @@ pub trait RecoverableScope<'ctx, E: Effect> { fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E>; } -pub type DynRecoverableScope<'a, 'ctx, E> = &'a mut (dyn RecoverableScope<'ctx, E> + Send + 'a); +pub type DynRecoverableScope<'a, 'ctx, E> = + &'a mut (dyn RecoverableScope<'ctx, E> + Send + Sync + 'a); pub struct RecoverableKnown; higher_ranked_type! { impl HintKnown { - impl['a] type T['a] for RecoverableKnown = + impl['a, 'ctx] type T['a, 'ctx] for RecoverableKnown = RecoverableKnown; - impl['a] type HigherRanked['a] for RecoverableKnown = + impl['a, 'ctx] type HigherRanked['a, 'ctx] for RecoverableKnown = RecoverableKnown; } } -impl<'ctx, E: Effect> HintMeta<'ctx> for RecoverableProto<E> { +impl<E: Effect> HintMeta for RecoverableProto<E> { type Known = RecoverableKnown; type Hint = (); diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index 831594f..c2f8837 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -1,5 +1,9 @@ use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_type, hkt::Marker, protocol::{Visitor, Walker} + any::TypeName, + effect::{Effect, Future}, + higher_ranked_type, + hkt::Marker, + protocol::{Visitor, Walker}, }; use super::VisitResult; @@ -21,12 +25,12 @@ pub struct RequestHintProto<E: Effect>(Marker<E>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, E] type T['a, 'ctx] for RequestHintProto<E> = - dyn RequestHint<'ctx, E> + Send + 'a + dyn RequestHint<'ctx, E> + Send + Sync + 'a where { E: Effect }; - impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn RequestHint<'ctx, E> + Send + 'a = + impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn RequestHint<'ctx, E> + Send + Sync + 'a = RequestHintProto<E> where { E: Effect diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index 32deb9c..afa6f9c 100644 --- a/src/protocol/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs @@ -1,5 +1,13 @@ use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_type, hkt::Marker, protocol::{walker::hint::{HintKnown, HintMeta}, Visitor}, Flow + any::TypeName, + effect::{Effect, Future}, + higher_ranked_type, + hkt::Marker, + protocol::{ + walker::hint::{HintKnown, HintMeta}, + Visitor, + }, + Flow, }; use super::VisitResult; @@ -16,12 +24,12 @@ pub struct SequenceProto<E: Effect>(Marker<E>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, E] type T['a, 'ctx] for SequenceProto<E> = - dyn Sequence<'ctx, E> + Send + 'a + dyn Sequence<'ctx, E> + Send + Sync + 'a where { E: Effect }; - impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn Sequence<'ctx, E> + Send + 'a = + impl['a, 'ctx, E] type HigherRanked['a, 'ctx] for dyn Sequence<'ctx, E> + Send + Sync + 'a = SequenceProto<E> where { E: Effect @@ -35,14 +43,14 @@ pub trait SequenceScope<'ctx, E: Effect> { fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>; } -pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + 'a); +pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + Sync + 'a); higher_ranked_type! { impl HintKnown { - impl['a] type T['a] for SequenceKnown = + impl['a, 'ctx] type T['a, 'ctx] for SequenceKnown = SequenceKnown; - impl['a] type HigherRanked['a] for SequenceKnown = + impl['a, 'ctx] type HigherRanked['a, 'ctx] for SequenceKnown = SequenceKnown; } } @@ -56,7 +64,7 @@ pub struct SequenceHint { pub len: (usize, Option<usize>), } -impl<'ctx, E: Effect> HintMeta<'ctx> for SequenceProto<E> { +impl<E: Effect> HintMeta for SequenceProto<E> { type Known = SequenceKnown; type Hint = SequenceHint; diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs index 1cfb29e..94828b4 100644 --- a/src/protocol/visitor/tag.rs +++ b/src/protocol/visitor/tag.rs @@ -1,10 +1,19 @@ use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_type, hkt::Marker, protocol::{walker::hint::{HintKnown, HintMeta}, Visitor}, symbol::Symbol, DynWalker, DynWalkerAdapter, DynWalkerError, WalkerTypes + any::TypeName, + effect::{Effect, Future}, + higher_ranked_type, + hkt::Marker, + protocol::{ + walker::hint::{HintKnown, HintMeta}, + Visitor, + }, + symbol::Symbol, + DynWalker, DynWalkerAdapter, DynWalkerError, WalkerTypes, }; use super::VisitResult; -pub trait TagKind: Copy + Send + 'static { +pub trait TagKind: Copy + Send + Sync + 'static { fn symbol(&self) -> Symbol; } @@ -39,13 +48,13 @@ pub struct TagProto<K: TagKind, E: Effect>(Marker<(K, E)>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, K, E] type T['a, 'ctx] for TagProto<K, E> = - dyn Tag<'ctx, K, E> + Send + 'a + dyn Tag<'ctx, K, E> + Send + Sync + 'a where { K: TagKind, E: Effect, }; - impl['a, 'ctx, K, E] type HigherRanked['a, 'ctx] for dyn Tag<'ctx, K, E> + Send + 'a = + impl['a, 'ctx, K, E] type HigherRanked['a, 'ctx] for dyn Tag<'ctx, K, E> + Send + Sync + 'a = TagProto<K, E> where { K: TagKind, @@ -56,10 +65,10 @@ higher_ranked_type! { higher_ranked_type! { impl HintKnown { - impl['a] type T['a] for TagKnown = + impl['a, 'ctx] type T['a, 'ctx] for TagKnown = TagKnown; - impl['a] type HigherRanked['a] for TagKnown = + impl['a, 'ctx] type HigherRanked['a, 'ctx] for TagKnown = TagKnown; } } @@ -72,7 +81,7 @@ pub struct TagHint<K> { pub kind: K, } -impl<'ctx, K: TagKind, E: Effect> HintMeta<'ctx> for TagProto<K, E> { +impl<K: TagKind, E: Effect> HintMeta for TagProto<K, E> { type Known = TagKnown; type Hint = TagHint<K>; diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index 5a6a2d8..b2ae696 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -3,7 +3,14 @@ //! In some sense, this is the most basic protocol. use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_type, hkt::Marker, protocol::{walker::hint::{HintKnown, HintMeta}, Visitor} + any::TypeName, + effect::{Effect, Future}, + higher_ranked_type, + hkt::Marker, + protocol::{ + walker::hint::{HintKnown, HintMeta}, + Visitor, + }, }; use super::VisitResult; @@ -35,13 +42,13 @@ pub struct ValueProto<T: ?Sized + TypeName::MemberType, E: Effect>(Marker<(*cons higher_ranked_type! { impl TypeName { impl['a, 'ctx, T, E] type T['a, 'ctx] for ValueProto<T, E> = - dyn Value<'ctx, T, E> + Send + 'a + dyn Value<'ctx, T, E> + Send + Sync + 'a where { T: ?Sized + TypeName::MemberType, E: Effect }; - impl['a, 'ctx, T, E] type HigherRanked['a, 'ctx] for dyn Value<'ctx, T, E> + Send + 'a = + impl['a, 'ctx, T, E] type HigherRanked['a, 'ctx] for dyn Value<'ctx, T, E> + Send + Sync + 'a = ValueProto<T, E> where { T: ?Sized + TypeName::MemberType, @@ -50,21 +57,36 @@ higher_ranked_type! { } } -pub struct ValueKnown; +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct ValueKnown<'a, T: ?Sized> { + /// A preview of the value. + /// + /// This can be used to inspect the value before committing to a visit. + pub preview: Option<&'a T>, +} + +#[derive(Copy, Clone, Debug)] +pub struct ValueKnownHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { impl HintKnown { - impl['a] type T['a] for ValueKnown = - ValueKnown; + impl['a, 'ctx, T] type T['a, 'ctx] for ValueKnownHrt<T> = + ValueKnown<'a, TypeName::T<'a, 'ctx, T>> + where { + T: ?Sized + TypeName::LowerForLt<'a, 'ctx, TypeName::Bound<'a, 'ctx>>, + }; - impl['a] type HigherRanked['a] for ValueKnown = - ValueKnown; + impl['a, 'ctx, T] type HigherRanked['a, 'ctx] for ValueKnown<'a, T> = + ValueKnownHrt<<T as TypeName::RaiseForLt<'a, 'ctx, TypeName::Bound<'a, 'ctx>>>::HigherRanked> + where { + T: ?Sized + TypeName::LowerType<'a, 'ctx>, + }; } } // This enrolls the Value protocol into the walker hint system. -impl<'a, 'ctx: 'a, T: TypeName::MemberType, E: Effect> HintMeta<'ctx> for ValueProto<T, E> { - type Known = ValueKnown; +impl<T: TypeName::MemberType, E: Effect> HintMeta for ValueProto<T, E> { + type Known = ValueKnownHrt<T>; type Hint = (); } @@ -72,12 +94,11 @@ impl<'a, 'ctx: 'a, T: TypeName::MemberType, E: Effect> HintMeta<'ctx> for ValueP pub fn visit_value<'a, 'ctx, T: Send + TypeName::LowerType<'a, 'ctx>, E: Effect>( visitor: Visitor<'a, 'ctx>, value: T, -) -> Future<'a, VisitResult<T>, E> +) -> Future<'a, VisitResult<T>, E> where - TypeName::HigherRanked<'a, 'ctx, T>: TypeName::MemberType + TypeName::HigherRanked<'a, 'ctx, T>: TypeName::MemberType, { - if let Some(object) = - visitor.upcast_mut::<ValueProto<TypeName::HigherRanked<'a, 'ctx, T>, E>>() + if let Some(object) = visitor.upcast_mut::<ValueProto<TypeName::HigherRanked<'a, 'ctx, T>, E>>() { // Allow the visitor to give a hint if it wants. object.visit(value) diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs index a4d51d5..9bb35e6 100644 --- a/src/protocol/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -5,14 +5,19 @@ //! to the walker about what it is expecting. use crate::{ - any::{TypeName}, effect::{Effect, Future}, higher_ranked_trait, higher_ranked_type, hkt::Marker, protocol::Visitor, Flow + any::TypeName, + effect::{Effect, Future}, + higher_ranked_trait, higher_ranked_type, + hkt::Marker, + protocol::Visitor, + Flow, }; higher_ranked_trait! { - pub type class HintKnown for<'a> { - type Bound = &'a (); + pub type class HintKnown for<'a, 'ctx> { + type Bound = &'a &'ctx (); - type T: { Send + Sized }; + type T: { Send + Sized } where { 'ctx: 'a }; type HigherRanked: { }; } @@ -21,7 +26,7 @@ higher_ranked_trait! { /// Meta information for the hint. /// /// This gives the visitor more information to work from when selecting a hint. -pub trait HintMeta<'ctx> { +pub trait HintMeta: Send + Sync + 'static { /// Information known by the walker. /// /// This should be information easy to get without changing the state of the walker @@ -32,23 +37,23 @@ pub trait HintMeta<'ctx> { type Hint; } -pub type Known<'a, 'ctx, Protocol> = HintKnown::T<'a, <Protocol as HintMeta<'ctx>>::Known>; +pub type Known<'a, 'ctx, Protocol> = HintKnown::T<'a, 'ctx, <Protocol as HintMeta>::Known>; /// Object implementing the [`Hint`] protocol. -pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>, E: Effect> { +pub trait Hint<'ctx, Protocol: ?Sized + HintMeta, E: Effect> { /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - hint: <Protocol as HintMeta<'ctx>>::Hint, + hint: <Protocol as HintMeta>::Hint, ) -> Future<'a, Flow, E>; /// Ask the walker for information about it's support of the protocol. fn known<'a>( &'a mut self, - hint: &'a <Protocol as HintMeta<'ctx>>::Hint, + hint: &'a <Protocol as HintMeta>::Hint, ) -> Future<'a, Result<Known<'a, 'ctx, Protocol>, ()>, E>; } @@ -57,13 +62,13 @@ pub struct HintProto<Protocol: ?Sized, E: Effect>(Marker<(*const Protocol, E)>); higher_ranked_type! { impl TypeName { impl['a, 'ctx, Protocol, E] type T['a, 'ctx] for HintProto<Protocol, E> = - dyn Hint<'ctx, Protocol, E> + Send + 'a + dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a where { Protocol: 'static, E: Effect }; - impl['a, 'ctx, Protocol, E] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol, E> + Send + 'a = + impl['a, 'ctx, Protocol, E] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a = HintProto<Protocol, E> where { Protocol: 'static, diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs index 21f48bd..93e8bba 100644 --- a/src/walk/walkers/core/struct.rs +++ b/src/walk/walkers/core/struct.rs @@ -8,10 +8,13 @@ use crate::{ never::Never, protocol::{ visitor::{ - visit_recoverable, visit_request_hint, visit_sequence, visit_tag, visit_value, RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto, SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown, ValueProto, VisitResult + visit_recoverable, visit_request_hint, visit_sequence, visit_tag, visit_value, + RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto, + SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown, + ValueProto, VisitResult, }, - walker::hint::{HintMeta, HintProto}, walker::hint::{Hint, Known}, + walker::hint::{HintMeta, HintProto}, Visitor, }, Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME, @@ -46,10 +49,10 @@ pub trait StructTypeInfo<'ctx, M>: 'static { const FIELDS: &'static [&'static str]; /// The walking errors for the fields. - type FieldError: Send; + type FieldError: Send + Sync; /// The struct being described. - type T: Send; + type T: Send + Sync; /// Walk the given field. fn walk_field<'a, E: Effect>( @@ -110,7 +113,7 @@ impl<'ctx, T, I, E, M> crate::Walker<'ctx, E> for StructWalker<'ctx, T, I, M, E> where E: Effect, I: StructTypeInfo<'ctx, M, T = T>, - T: Sync + 'static, + T: Send + Sync + 'static, { fn walk<'a>( mut self, @@ -145,7 +148,7 @@ any_trait! { HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>, ] where E: Effect, - T: Sync + 'static, + T: Send + Sync + 'static, I: StructTypeInfo<'ctx, M, T = T> } @@ -153,12 +156,12 @@ impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>, E> for StructWalker<'ctx, where E: Effect, I: StructTypeInfo<'ctx, M, T = T>, - T: Sync + 'static, + T: Send + Sync + 'static, { fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <RecoverableProto<E> as HintMeta<'ctx>>::Hint, + _hint: <RecoverableProto<E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_recoverable::<E>(visitor, self), @@ -171,7 +174,7 @@ where fn known<'a>( &'a mut self, - _hint: &'a <RecoverableProto<E> as HintMeta<'ctx>>::Hint, + _hint: &'a <RecoverableProto<E> as HintMeta>::Hint, ) -> Future<'a, Result<Known<'a, 'ctx, RecoverableProto<E>>, ()>, E> { E::ready(Ok(RecoverableKnown)) } @@ -187,7 +190,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>( @@ -208,9 +211,7 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta< - 'ctx, - >>::Hint, + _hint: &'a <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint, ) -> Future< 'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>, @@ -232,7 +233,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>( @@ -253,12 +254,9 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta<'ctx>>::Hint, - ) -> Future< - 'a, - Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>, - E, - > { + _hint: &'a <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta>::Hint, + ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>, E> + { E::ready(Ok(TagKnown { kind_available: Some(true), })) @@ -275,7 +273,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()), @@ -292,7 +290,7 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: &'a <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, ()>, E> { E::ready(Ok(TagKnown { @@ -311,7 +309,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>( @@ -332,12 +330,9 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta<'ctx>>::Hint, - ) -> Future< - 'a, - Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>, - E, - > { + _hint: &'a <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta>::Hint, + ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>, E> + { E::ready(Ok(TagKnown { kind_available: Some(true), })) @@ -354,7 +349,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta<'ctx>>::Hint, + _hint: <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>( @@ -375,12 +370,9 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta<'ctx>>::Hint, - ) -> Future< - 'a, - Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>, - E, - > { + _hint: &'a <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta>::Hint, + ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>, E> + { E::ready(Ok(TagKnown { kind_available: Some(true), })) @@ -396,28 +388,28 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - hint: <TagProto<TagDyn, E> as HintMeta<'ctx>>::Hint, + hint: <TagProto<TagDyn, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { match hint.kind.0 { - crate::TAG_TYPE_ID => Hint::< - 'ctx, - TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, - E, - >::hint(self, visitor, TagHint { kind: TagConst }), - crate::TAG_STRUCT => { - Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>::hint( + crate::TAG_TYPE_ID => { + Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>::hint( self, visitor, TagHint { kind: TagConst }, ) } - crate::TAG_MAP => { - Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>::hint( + crate::TAG_STRUCT => { + Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>::hint( self, visitor, TagHint { kind: TagConst }, ) } + crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>::hint( + self, + visitor, + TagHint { kind: TagConst }, + ), crate::TAG_TYPE_NAME => Hint::< 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, @@ -434,7 +426,7 @@ where fn known<'a>( &'a mut self, - hint: &'a <TagProto<TagDyn, E> as HintMeta<'ctx>>::Hint, + hint: &'a <TagProto<TagDyn, E> as HintMeta>::Hint, ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagDyn, E>>, ()>, E> { E::ready(match hint.kind { TagDyn(crate::TAG_TYPE_ID) | TagDyn(crate::TAG_STRUCT) => Ok(TagKnown { @@ -452,7 +444,7 @@ impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>, E> where E: Effect, I: StructTypeInfo<'ctx, M>, - T: Sync + 'static, + T: Send + Sync + 'static, { fn hint<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> { E::map( @@ -464,8 +456,11 @@ where ) } - fn known<'a>(&'a mut self, _hint: &'a ()) -> Future<'a, Result<ValueKnown, ()>, E> { - E::ready(Ok(ValueKnown)) + fn known<'a>( + &'a mut self, + _hint: &'a (), + ) -> Future<'a, Result<ValueKnown<'a, BorrowedStatic<'ctx, T>>, ()>, E> { + E::ready(Ok(ValueKnown { preview: None })) } } @@ -478,7 +473,7 @@ where fn hint<'a>( &'a mut self, visitor: Visitor<'a, 'ctx>, - _hint: <SequenceProto<E> as HintMeta<'ctx>>::Hint, + _hint: <SequenceProto<E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map(visit_sequence::<E>(visitor, self), |status| match status { VisitResult::Skipped(_) => Flow::Continue, @@ -488,7 +483,7 @@ where fn known<'a>( &'a mut self, - _hint: &'a <SequenceProto<E> as HintMeta<'ctx>>::Hint, + _hint: &'a <SequenceProto<E> as HintMeta>::Hint, ) -> Future<'a, Result<Known<'a, 'ctx, SequenceProto<E>>, ()>, E> { let len = I::FIELDS.len(); @@ -535,7 +530,7 @@ impl<'ctx, T, I, M, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, T, I, M, where E: Effect, I: StructTypeInfo<'ctx, M, T = T>, - T: Sync + 'static, + T: Send + Sync + 'static, { fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E> { // Reset the errors to default state. diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs index 9728b00..a4f1cea 100644 --- a/src/walk/walkers/core/tag.rs +++ b/src/walk/walkers/core/tag.rs @@ -7,7 +7,7 @@ use crate::{ never::Never, protocol::{ visitor::{ - visit_request_hint, visit_value, SequenceProto, SequenceScope, TagError, VisitResult + visit_request_hint, visit_value, SequenceProto, SequenceScope, TagError, VisitResult, }, Visitor, }, diff --git a/src/walk/walkers/core/value.rs b/src/walk/walkers/core/value.rs index 2654a6c..b8e5b79 100644 --- a/src/walk/walkers/core/value.rs +++ b/src/walk/walkers/core/value.rs @@ -38,7 +38,7 @@ impl<T> WalkerTypes for ValueWalker<T> { type Output = (); } -impl<'ctx, T: Send + 'static, E: Effect> crate::Walker<'ctx, E> for ValueWalker<T> { +impl<'ctx, T: Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E> for ValueWalker<T> { fn walk<'a>( self, visitor: Visitor<'a, 'ctx>, @@ -72,7 +72,9 @@ impl<'ctx, T: ?Sized> WalkerTypes for BorrowWalker<'ctx, T> { type Output = (); } -impl<'ctx, T: ?Sized + Sync + 'static, E: Effect> crate::Walker<'ctx, E> for BorrowWalker<'ctx, T> { +impl<'ctx, T: ?Sized + Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E> + for BorrowWalker<'ctx, T> +{ fn walk<'a>( self, visitor: Visitor<'a, 'ctx>, diff --git a/tests/common/protocol.rs b/tests/common/protocol.rs index 8320dc3..148a458 100644 --- a/tests/common/protocol.rs +++ b/tests/common/protocol.rs @@ -1,2 +1,3 @@ +pub mod hint; pub mod tag; pub mod visitor; diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs new file mode 100644 index 0000000..bcc2a02 --- /dev/null +++ b/tests/common/protocol/hint.rs @@ -0,0 +1,46 @@ +use mockall::mock; +use treaty::{ + any::{any_trait, TypeName}, + effect::{Effect, Future}, + protocol::{ + walker::hint::{Hint, HintMeta, HintProto, Known}, + Visitor, + }, + Flow, +}; + +pub type KnownFactory<P> = + for<'a, 'ctx> fn(&'ctx (), &'a <P as HintMeta>::Hint) -> Result<Known<'a, 'ctx, P>, ()>; + +mock! { + pub HintVisitor<P: HintMeta, E> { + pub fn hint<'a, 'ctx>(&'a mut self, visitor: Visitor<'a, 'ctx>, hint: <P as HintMeta>::Hint) -> Flow; + + pub fn known(&self) -> KnownFactory<P>; + } +} + +any_trait! { + impl['ctx, P, E] MockHintVisitor<P, E> = [ + HintProto<P, E> + ] where + P: HintMeta, + E: Effect, +} + +impl<'ctx, P: HintMeta, E: Effect> Hint<'ctx, P, E> for MockHintVisitor<P, E> { + fn hint<'a>( + &'a mut self, + visitor: Visitor<'a, 'ctx>, + hint: <P as HintMeta>::Hint, + ) -> Future<'a, Flow, E> { + E::ready(self.hint(visitor, hint)) + } + + fn known<'a>( + &'a mut self, + hint: &'a <P as HintMeta>::Hint, + ) -> Future<'a, Result<Known<'a, 'ctx, P>, ()>, E> { + E::ready(Self::known(self)(&(), hint)) + } +} diff --git a/tests/common/protocol/tag.rs b/tests/common/protocol/tag.rs index a8f6c35..7bc152a 100644 --- a/tests/common/protocol/tag.rs +++ b/tests/common/protocol/tag.rs @@ -2,7 +2,7 @@ use mockall::mock; use treaty::{ any::any_trait, effect::{Effect, Future}, - protocol::visitor::{TagProto, Tag, TagKind, VisitResult}, + protocol::visitor::{Tag, TagKind, TagProto, VisitResult}, DynWalker, }; diff --git a/tests/common/protocol/visitor.rs b/tests/common/protocol/visitor.rs index b79596d..f980bc5 100644 --- a/tests/common/protocol/visitor.rs +++ b/tests/common/protocol/visitor.rs @@ -2,7 +2,7 @@ use mockall::mock; use treaty::{ any::{any_trait, TypeName}, effect::{Effect, Future}, - protocol::visitor::{ValueProto, Value, VisitResult}, + protocol::visitor::{Value, ValueProto, VisitResult}, Flow, }; @@ -11,7 +11,7 @@ mock! { where for<'a, 'ctx> TypeName::T<'a, 'ctx, T>: Sized { - pub fn visit<'a, 'ctx>(&'a mut self, value: TypeName::T<'a, 'ctx, T>) -> VisitResult<()>; + pub fn visit<'a, 'ctx>(&'a mut self, value: &TypeName::T<'a, 'ctx, T>) -> VisitResult<()>; } } @@ -19,15 +19,14 @@ any_trait! { impl['ctx, T, E] MockValueVisitor<T, E> = [ ValueProto<T, E> ] where - T: TypeName::MemberType + Send, + T: TypeName::MemberType, for<'a, 'b> TypeName::T<'a, 'b, T>: Clone + Sized, E: Effect, } -impl<'ctx, T: TypeName::MemberType, E: Effect> Value<'ctx, T, E> - for MockValueVisitor<T, E> +impl<'ctx, T: TypeName::MemberType, E: Effect> Value<'ctx, T, E> for MockValueVisitor<T, E> where - for<'a, 'lt> TypeName::T<'a, 'lt, T>: Sized + Clone, + for<'a, 'lt> TypeName::T<'a, 'lt, T>: Sized, { fn visit<'a>( &'a mut self, @@ -37,7 +36,7 @@ where TypeName::T<'a, 'ctx, T>: Send, 'ctx: 'a, { - E::ready(match self.visit(value.clone()) { + E::ready(match self.visit(&value) { VisitResult::Skipped(_) => VisitResult::Skipped(value), VisitResult::Control(flow) => VisitResult::Control(flow), }) diff --git a/tests/protocol_visitor_value.rs b/tests/protocol_visitor_value.rs index 8b13789..ff17fc4 100644 --- a/tests/protocol_visitor_value.rs +++ b/tests/protocol_visitor_value.rs @@ -1 +1,271 @@ +use std::any::TypeId; +use common::protocol::{ + hint::{KnownFactory, MockHintVisitor}, + visitor::MockValueVisitor, +}; +use mockall::predicate::eq; +use treaty::{ + any::{ + BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic, + TempBorrowedMutStaticHrt, TypeNameId, + }, + effect::Blocking, + protocol::{ + visitor::{Value, ValueKnown, ValueProto, VisitResult}, + walker::hint::Hint, + }, + Flow, +}; + +mod common; + +/// Tests support for custom type support in the value protocol. +/// +/// This is a core feature of treaty so it better work. +#[test] +fn custom_value_type() { + // The value we want to visit in the value visitor. + #[derive(PartialEq, Debug, Clone)] + struct MyValue; + + let mut mock = MockValueVisitor::<OwnedStatic<MyValue>, Blocking>::new(); + + // Expect the visit method to be called once with the custom type. + mock.expect_visit() + .once() + .with(eq(OwnedStatic(MyValue))) + .return_const(VisitResult::Control(Flow::Done)); + + // Cast to a trait object for the value protocol. + // This shows the visit method is going through the trait. + let visitor: &mut dyn Value<OwnedStatic<MyValue>, Blocking> = &mut mock; + + // Visit the value. + let result = visitor.visit(OwnedStatic(MyValue)).into_innter(); + + // The mock returns that it is done. + assert_eq!(result, VisitResult::Control(Flow::Done)); +} + +/// Tests that a value with a lifetime can be given to the value protocol. +/// +/// This allows for treaty's zero copy capabilities. +/// Also this is what allows treaty to short circuit things like structs and enums if the visitor +/// supports it. +#[test] +fn borrowed_value() { + // A value with a lifetime longer than the visitor. + let context = String::from("test"); + + // Scope that doesn't live as long as the context. + { + // We borrow the context, this is what we pass to the visitor. + let value = &context; + + let mut mock = MockValueVisitor::<BorrowedStaticHrt<String>, Blocking>::new(); + + // Expect the visit method to be called once with the borrowed value. + mock.expect_visit() + .once() + .withf(|BorrowedStatic(value)| *value == "test") + .return_const(VisitResult::Control(Flow::Done)); + + // Cast to a trait object for the value protocol. + let visitor: &mut dyn Value<BorrowedStaticHrt<String>, Blocking> = &mut mock; + + // Visit the borrowed value. + visitor.visit(BorrowedStatic(value)); + } + + // Make sure the compiler doesn't do anything funny with the lifetime. + assert_eq!(context, "test"); +} + +/// Tests that a value with a temp lifetime can be given to the value protocol. +/// +/// This is useful for passing borrows of things inside a walker to a visitor. +/// The visitor can't keep the borrow as the temp lifetime is shorter than the context. +/// +/// If you replaced the [`TempBorrowedMutStaticHrt`] with [`BorrowedMutStaticHrt`] +/// this would fail to compile. +#[test] +fn temp_borrowed_value() { + // A value with a lifetime longer than the visitor. + let mut context = String::from("test"); + + // Scope that doesn't live as long as the context. + { + // We borrow the context, this is what we pass to the visitor. + let value = &mut context; + + let mut mock = MockValueVisitor::<TempBorrowedMutStaticHrt<String>, Blocking>::new(); + + // Expect the visit method to be called once with the borrowed value. + mock.expect_visit() + .times(2) + .withf(|TempBorrowedMutStatic(value)| *value == "test") + .return_const(VisitResult::Control(Flow::Done)); + + // Cast to a trait object for the value protocol. + // We definitly need this for this test so the lifetime is invariant. + let visitor: &mut dyn Value<TempBorrowedMutStaticHrt<String>, Blocking> = &mut mock; + + // Visit the context to show we can shorten the lifetime. + // This would also force the lifetime to be to long if this wasn't the Temp form. + visitor.visit(TempBorrowedMutStatic(value)); + + // Temporary scope (smaller than the context we set above). + { + // A temporary value. + let mut value = String::from("test"); + + // Visit the temp value. + visitor.visit(TempBorrowedMutStatic(&mut value)); + } + + // Force the visitor to outlive the temporary scope. + let _ = visitor; + } + + // Make sure the compiler doesn't do anything funny with the lifetime. + assert_eq!(context, "test"); +} + +/// Tests for the control flow returns the value protocol visit can return. +#[test] +fn all_visit_results() { + let mut mock = MockValueVisitor::<OwnedStatic<i32>, Blocking>::new(); + + mock.expect_visit() + .once() + .with(eq(OwnedStatic(0))) + .return_const(VisitResult::Control(Flow::Done)); + + mock.expect_visit() + .once() + .with(eq(OwnedStatic(1))) + .return_const(VisitResult::Control(Flow::Err)); + + mock.expect_visit() + .once() + .with(eq(OwnedStatic(2))) + .return_const(VisitResult::Control(Flow::Continue)); + + mock.expect_visit() + .once() + .with(eq(OwnedStatic(3))) + .return_const(VisitResult::Skipped(())); + + let visitor: &mut dyn Value<OwnedStatic<i32>, Blocking> = &mut mock; + + // Visit can return a done. + assert_eq!( + visitor.visit(OwnedStatic(0)).into_innter(), + VisitResult::Control(Flow::Done) + ); + + // Visit can return an error signal. + assert_eq!( + visitor.visit(OwnedStatic(1)).into_innter(), + VisitResult::Control(Flow::Err) + ); + + // Visit can return a continue. + assert_eq!( + visitor.visit(OwnedStatic(2)).into_innter(), + VisitResult::Control(Flow::Continue) + ); + + // A visit can be skipped. + // This is for runtime visit support checking. + // The value should be given back, but that's not forced. + assert_eq!( + visitor.visit(OwnedStatic(3)).into_innter(), + VisitResult::Skipped(OwnedStatic(3)) + ); +} + +/// Tests that the higher ranked name for the value protocol exists. +#[test] +fn value_proto() { + // The type id of the higher ranked type. + let id = TypeId::of::<ValueProto<OwnedStatic<i32>, Blocking>>(); + + // The type id for the lifetime containing value protocol trait object. + let name_id = TypeNameId::of_lower::<dyn Value<OwnedStatic<i32>, Blocking> + Send + Sync>(); + + // They should be the same. + assert_eq!(id, name_id.into_type_id()); +} + +/// Tests that the value protocol can be given as a hint to a walker. +/// +/// The value protocol allows a hint of a preview of the value. +#[test] +fn as_hint() { + { + let mut mock = MockHintVisitor::<ValueProto<OwnedStatic<i32>, Blocking>, Blocking>::new(); + + mock.expect_known().once().return_const( + (|_, _hint| { + Ok(ValueKnown { + preview: Some(&OwnedStatic(42)), + }) + }) as KnownFactory<ValueProto<OwnedStatic<i32>, Blocking>>, + ); + + let walker: &mut dyn Hint<ValueProto<OwnedStatic<i32>, Blocking>, Blocking> = &mut mock; + + // The value protocol has no hint data, and it has no known data. + assert_eq!( + walker.known(&()).into_innter(), + Ok(ValueKnown { + preview: Some(&OwnedStatic(42)) + }) + ); + } + + { + let mut mock = + MockHintVisitor::<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking>::new(); + + mock.expect_known().once().return_const( + (|_, _hint| { + Ok(ValueKnown { + preview: Some(&BorrowedStatic(&42)), + }) + }) as KnownFactory<ValueProto<BorrowedStaticHrt<i32>, Blocking>>, + ); + + let walker: &mut dyn Hint<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking> = + &mut mock; + + // The value protocol has no hint data, and it has no known data. + assert_eq!( + walker.known(&()).into_innter(), + Ok(ValueKnown { + preview: Some(&BorrowedStatic(&42)) + }) + ); + } + + { + let mut mock = + MockHintVisitor::<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>, Blocking>::new(); + + mock.expect_known().once().return_const( + (|_, _hint| Ok(ValueKnown { preview: None })) + as KnownFactory<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>>, + ); + + let walker: &mut dyn Hint<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>, Blocking> = + &mut mock; + + // The value protocol has no hint data, and it has no known data. + assert_eq!( + walker.known(&()).into_innter(), + Ok(ValueKnown { preview: None }) + ); + } +} |