-rw-r--r--src/any.rs53
-rw-r--r--src/any/static_wrapper.rs28
-rw-r--r--src/any/type_name_id.rs15
-rw-r--r--src/build/builders/debug.rs5
-rw-r--r--src/effect.rs42
-rw-r--r--src/hkt.rs24
-rw-r--r--src/protocol/visitor.rs2
-rw-r--r--src/protocol/visitor/recoverable.rs23
-rw-r--r--src/protocol/visitor/request_hint.rs10
-rw-r--r--src/protocol/visitor/sequence.rs22
-rw-r--r--src/protocol/visitor/tag.rs23
-rw-r--r--src/protocol/visitor/value.rs49
-rw-r--r--src/protocol/walker/hint.rs27
-rw-r--r--src/walk/walkers/core/struct.rs101
-rw-r--r--src/walk/walkers/core/tag.rs2
-rw-r--r--src/walk/walkers/core/value.rs6
-rw-r--r--tests/common/protocol.rs1
-rw-r--r--tests/common/protocol/hint.rs46
-rw-r--r--tests/common/protocol/tag.rs2
-rw-r--r--tests/common/protocol/visitor.rs13
-rw-r--r--tests/protocol_visitor_value.rs270
21 files changed, 579 insertions, 185 deletions
diff --git a/src/any.rs b/src/any.rs
index 3207f02..411f660 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -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)),
+ }
}
}
diff --git a/src/hkt.rs b/src/hkt.rs
index 55e9856..e019bf9 100644
--- a/src/hkt.rs
+++ b/src/hkt.rs
@@ -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 })
+ );
+ }
+}