added more tests, rustc ICE
Konnor Andrews 2024-04-20
parent 9635ea7 · commit 5cae837
-rw-r--r--.gitignore2
-rw-r--r--src/any.rs8
-rw-r--r--src/build.rs14
-rw-r--r--src/build/builders/core/bool.rs6
-rw-r--r--src/build/builders/debug.rs25
-rw-r--r--src/effect.rs2
-rw-r--r--src/protocol.rs47
-rw-r--r--src/protocol/visitor/recoverable.rs14
-rw-r--r--src/protocol/visitor/request_hint.rs14
-rw-r--r--src/protocol/visitor/sequence.rs36
-rw-r--r--src/protocol/visitor/tag.rs40
-rw-r--r--src/protocol/visitor/value.rs177
-rw-r--r--src/protocol/walker/hint.rs111
-rw-r--r--src/transform.rs85
-rw-r--r--src/walk.rs16
-rw-r--r--src/walk/walkers/core/key_value.rs12
-rw-r--r--src/walk/walkers/core/noop.rs4
-rw-r--r--src/walk/walkers/core/struct.rs139
-rw-r--r--src/walk/walkers/core/tag.rs13
-rw-r--r--src/walk/walkers/core/value.rs6
-rw-r--r--tests/common/builder.rs16
-rw-r--r--tests/common/mod.rs1
-rw-r--r--tests/common/protocol.rs2
-rw-r--r--tests/common/protocol/hint.rs31
-rw-r--r--tests/common/protocol/request_hint.rs33
-rw-r--r--tests/common/protocol/sequence.rs58
-rw-r--r--tests/common/protocol/tag.rs8
-rw-r--r--tests/common/walker.rs57
-rw-r--r--tests/protocol_visitor_request_hint.rs93
-rw-r--r--tests/protocol_visitor_sequence.rs76
-rw-r--r--tests/protocol_visitor_tag.rs44
-rw-r--r--tests/protocol_visitor_value.rs55
-rw-r--r--tests/protocol_walker_hint.rs313
-rw-r--r--tests/walk.rs3
-rw-r--r--tests/walkers/core.rs1
-rw-r--r--tests/walkers/core/struct.rs146
-rw-r--r--tests/walkers/mod.rs1
37 files changed, 1096 insertions, 613 deletions
diff --git a/.gitignore b/.gitignore
index ea8c4bf..f7995c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
/target
+/target-bisector-*
+rustc-ice-*
diff --git a/src/any.rs b/src/any.rs
index 411f660..3ebc7b2 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -100,7 +100,7 @@ higher_ranked_type! {
///
/// // Cast to be a AnyTrait trait object.
/// // Now we don't know the type.
-/// let anything: &(dyn AnyTrait<'_> + Send) = &my_num;
+/// let anything: &(dyn AnyTrait<'_> + Send + Sync) = &my_num;
///
/// // We can still upcast to an impl of ToNum.
/// let to_num_object: &dyn ToNum = anything.upcast::<DynToNum>().unwrap();
@@ -173,7 +173,7 @@ pub trait AnyTrait<'ctx> {
'ctx: 'a;
}
-impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + 'b {
+impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + Sync + 'b {
/// Upcast a borrow to the given trait object type.
///
/// This should be used instead of [`upcast_to_id`][AnyTrait::upcast_to_id]
@@ -407,7 +407,9 @@ 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 + Sync))
+ .upcast::<DynZ>()
+ .unwrap();
assert_eq!(y.get(), 42);
}
diff --git a/src/build.rs b/src/build.rs
index f4476f0..716b882 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -2,23 +2,23 @@ pub mod builders;
use crate::{
effect::{Effect, Future},
- protocol::Visitor,
+ protocol::DynVisitor,
};
/// A buildable type.
-pub trait Build<'ctx, M, E: Effect>: BuilderTypes<Value = Self> + Send {
+pub trait Build<'ctx, M, E: Effect>: BuilderTypes<Value = Self> + Send + Sync {
/// The builder that can be used to build a value of `Self`.
type Builder: Builder<'ctx, E, Seed = Self::Seed, Error = Self::Error, Value = Self>;
}
pub trait BuilderTypes {
- type Seed: Send;
+ type Seed: Send + Sync;
/// Error that can happen during filling the builder with data.
- type Error: Send;
+ type Error: Send + Sync;
/// Type to be built.
- type Value: Send;
+ type Value: Send + Sync;
}
/// Builder for a type.
@@ -34,7 +34,7 @@ pub trait BuilderTypes {
/// the builder with data from it's walk.
/// - Call [`Self::build()`] to finish building the value and get any errors
/// that happened during filling it with data.
-pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send {
+pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send + Sync {
fn from_seed<'a>(seed: Self::Seed) -> Future<'a, Self, E>
where
Self: 'a;
@@ -50,5 +50,5 @@ pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send {
/// Get the builder as a visitor that a walker can use.
///
/// This is expected to just be `self`.
- fn as_visitor(&mut self) -> Visitor<'_, 'ctx>;
+ fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx>;
}
diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs
index f122e8a..29b6ab0 100644
--- a/src/build/builders/core/bool.rs
+++ b/src/build/builders/core/bool.rs
@@ -6,7 +6,7 @@ use crate::{
effect::{Effect, Future},
protocol::{
visitor::{Value, ValueProto, VisitResult},
- Visitor,
+ DynVisitor,
},
Flow,
};
@@ -54,8 +54,8 @@ impl<'ctx, E: Effect> crate::Builder<'ctx, E> for Builder<E> {
E::wrap(core::future::ready(Self(None, PhantomData)))
}
- fn as_visitor(&mut self) -> Visitor<'_, 'ctx> {
- self
+ fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
+ DynVisitor(self)
}
}
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs
index b7331a1..cb447b6 100644
--- a/src/build/builders/debug.rs
+++ b/src/build/builders/debug.rs
@@ -5,14 +5,13 @@ use crate::{
any_trait,
effect::{Effect, Future},
protocol::{
- self,
- visitor::{
+ self, visitor::{
DynSequenceScope, RequestHint, RequestHintProto, Sequence, Tag, TagDyn, TagProto,
Value, ValueProto, VisitResult,
- },
+ }, DynVisitor
},
- protocol::{visitor::SequenceProto, Walker},
- DynWalker, Flow,
+ protocol::{visitor::SequenceProto, DynWalker},
+ DynWalkerObjSafe, Flow,
};
pub struct Visitor<E>(usize, PhantomData<fn() -> E>);
@@ -59,8 +58,8 @@ impl<E: Effect> Visitor<E> {
impl<'ctx, E: Effect> RequestHint<'ctx, E> for Visitor<E> {
fn request_hint<'a>(
&'a mut self,
- _walker: Walker<'a, 'ctx>,
- ) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E> {
+ _walker: DynWalker<'a, 'ctx>,
+ ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
// self.tab();
// println!("Visit request hint (no hint given)");
// println!("Visit request hint (hint for recoverable)");
@@ -72,8 +71,8 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> {
fn visit<'a>(
&'a mut self,
kind: TagDyn,
- walker: DynWalker<'a, 'ctx, E>,
- ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E> {
+ walker: DynWalkerObjSafe<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> {
E::wrap(async move {
match kind.0 {
crate::TAG_TYPE_NAME => {
@@ -81,7 +80,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> {
println!("type name:");
self.0 += 1;
- let _ = walker.walk(self).await;
+ let _ = walker.walk(DynVisitor(self)).await;
self.0 -= 1;
Flow::Continue.into()
@@ -91,7 +90,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> {
println!("key:");
self.0 += 1;
- let _ = walker.walk(self).await;
+ let _ = walker.walk(DynVisitor(self)).await;
self.0 -= 1;
Flow::Continue.into()
@@ -101,7 +100,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> {
println!("value:");
self.0 += 1;
- let _ = walker.walk(self).await;
+ let _ = walker.walk(DynVisitor(self)).await;
self.0 -= 1;
Flow::Continue.into()
@@ -199,7 +198,7 @@ impl<'ctx, E: Effect> Sequence<'ctx, E> for Visitor<E> {
println!("{}:", index);
self.0 += 1;
- match scope.next(self).await {
+ match scope.next(DynVisitor(self)).await {
Flow::Done => {
self.tab();
println!("<end>");
diff --git a/src/effect.rs b/src/effect.rs
index 1d10cbc..cf8cbdd 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -111,7 +111,7 @@ pub struct Ready<Output> {
}
impl<Output> Ready<Output> {
- pub fn into_innter(self) -> Output {
+ pub fn into_inner(self) -> Output {
self.value.expect("`into_inner` called after completion")
}
}
diff --git a/src/protocol.rs b/src/protocol.rs
index 33d73be..822d827 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -55,7 +55,50 @@
pub mod visitor;
pub mod walker;
+use core::ops::{Deref, DerefMut};
+
use crate::any::AnyTrait;
-pub type Visitor<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a);
-pub type Walker<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a);
+pub struct DynVisitor<'a, 'ctx>(pub &'a mut (dyn AnyTrait<'ctx> + Send + Sync + 'a));
+
+impl<'a, 'ctx> DynVisitor<'a, 'ctx> {
+ pub fn cast<'b>(&'b mut self) -> DynVisitor<'b, 'ctx> {
+ DynVisitor(&mut *self.0)
+ }
+}
+
+impl<'a, 'ctx> Deref for DynVisitor<'a, 'ctx> {
+ type Target = dyn AnyTrait<'ctx> + Send + Sync + 'a;
+
+ fn deref(&self) -> &Self::Target {
+ &*self.0
+ }
+}
+
+impl<'a, 'ctx> DerefMut for DynVisitor<'a, 'ctx> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut *self.0
+ }
+}
+
+pub struct DynWalker<'a, 'ctx>(pub &'a mut (dyn AnyTrait<'ctx> + Send + Sync + 'a));
+
+impl<'a, 'ctx> DynWalker<'a, 'ctx> {
+ pub fn cast<'b>(&'b mut self) -> DynVisitor<'b, 'ctx> {
+ DynVisitor(&mut *self.0)
+ }
+}
+
+impl<'a, 'ctx> Deref for DynWalker<'a, 'ctx> {
+ type Target = dyn AnyTrait<'ctx> + Send + Sync + 'a;
+
+ fn deref(&self) -> &Self::Target {
+ &*self.0
+ }
+}
+
+impl<'a, 'ctx> DerefMut for DynWalker<'a, 'ctx> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut *self.0
+ }
+}
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs
index 4c9c604..b0d14de 100644
--- a/src/protocol/visitor/recoverable.rs
+++ b/src/protocol/visitor/recoverable.rs
@@ -4,8 +4,8 @@ use crate::{
higher_ranked_type,
hkt::Marker,
protocol::{
- walker::hint::{HintKnown, HintMeta},
- Visitor,
+ walker::hint::{HintMeta, Meta},
+ DynVisitor,
},
Status,
};
@@ -38,7 +38,7 @@ higher_ranked_type! {
}
pub trait RecoverableScope<'ctx, E: Effect> {
- fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E>;
+ fn new_walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E>;
}
pub type DynRecoverableScope<'a, 'ctx, E> =
@@ -47,7 +47,7 @@ pub type DynRecoverableScope<'a, 'ctx, E> =
pub struct RecoverableKnown;
higher_ranked_type! {
- impl HintKnown {
+ impl Meta {
impl['a, 'ctx] type T['a, 'ctx] for RecoverableKnown =
RecoverableKnown;
@@ -60,13 +60,15 @@ impl<E: Effect> HintMeta for RecoverableProto<E> {
type Known = RecoverableKnown;
type Hint = ();
+
+ type Effect = E;
}
pub fn visit_recoverable<'a, 'ctx, E: Effect>(
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
scope: DynRecoverableScope<'a, 'ctx, E>,
) -> Future<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> {
- if let Some(object) = visitor.upcast_mut::<RecoverableProto<E>>() {
+ if let Some(object) = visitor.0.upcast_mut::<RecoverableProto<E>>() {
// Allow the visitor to give a hint if it wants.
object.visit(scope)
} else {
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index c2f8837..1e699a1 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -3,7 +3,7 @@ use crate::{
effect::{Effect, Future},
higher_ranked_type,
hkt::Marker,
- protocol::{Visitor, Walker},
+ protocol::{DynVisitor, DynWalker},
};
use super::VisitResult;
@@ -16,8 +16,8 @@ pub trait RequestHint<'ctx, E: Effect> {
/// [`Hint`][crate::builtins::walker::Hint] protocol.
fn request_hint<'a>(
&'a mut self,
- walker: Walker<'a, 'ctx>,
- ) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E>;
+ walker: DynWalker<'a, 'ctx>,
+ ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E>;
}
pub struct RequestHintProto<E: Effect>(Marker<E>);
@@ -46,10 +46,10 @@ higher_ranked_type! {
/// should stop walking.
/// If [`Flow::Break`] is returned then there was an error and the walker should stop walking.
pub fn visit_request_hint<'a, 'ctx, E: Effect>(
- visitor: Visitor<'a, 'ctx>,
- walker: Walker<'a, 'ctx>,
-) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E> {
- if let Some(object) = visitor.upcast_mut::<RequestHintProto<E>>() {
+ visitor: DynVisitor<'a, 'ctx>,
+ walker: DynWalker<'a, 'ctx>,
+) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ if let Some(object) = visitor.0.upcast_mut::<RequestHintProto<E>>() {
// Allow the visitor to give a hint if it wants.
object.request_hint(walker)
} else {
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index afa6f9c..ef0c5e9 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -4,14 +4,18 @@ use crate::{
higher_ranked_type,
hkt::Marker,
protocol::{
- walker::hint::{HintKnown, HintMeta},
- Visitor,
+ walker::hint::{HintMeta, Meta},
+ DynVisitor,
},
Flow,
};
use super::VisitResult;
+/// Protocol for visiting a sequence.
+///
+/// This protocol uses a scope to give temporary control to the visitor.
+/// The visitor will drive the walker for each item.
pub trait Sequence<'ctx, E: Effect> {
fn visit<'a>(
&'a mut self,
@@ -40,13 +44,18 @@ higher_ranked_type! {
pub trait SequenceScope<'ctx, E: Effect> {
fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E>;
- fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>;
+ fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E>;
}
pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + Sync + 'a);
+#[derive(Default)]
+pub struct SequenceKnown {
+ pub len: (usize, Option<usize>),
+}
+
higher_ranked_type! {
- impl HintKnown {
+ impl Meta {
impl['a, 'ctx] type T['a, 'ctx] for SequenceKnown =
SequenceKnown;
@@ -55,26 +64,33 @@ higher_ranked_type! {
}
}
-#[derive(Default)]
-pub struct SequenceKnown {
+pub struct SequenceHint {
pub len: (usize, Option<usize>),
}
-pub struct SequenceHint {
- pub len: (usize, Option<usize>),
+higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for SequenceHint =
+ SequenceHint;
+
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for SequenceHint =
+ SequenceHint;
+ }
}
impl<E: Effect> HintMeta for SequenceProto<E> {
type Known = SequenceKnown;
type Hint = SequenceHint;
+
+ type Effect = E;
}
pub fn visit_sequence<'a, 'ctx, E: Effect>(
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
scope: DynSequenceScope<'a, 'ctx, E>,
) -> Future<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
- if let Some(object) = visitor.upcast_mut::<SequenceProto<E>>() {
+ if let Some(object) = visitor.0.upcast_mut::<SequenceProto<E>>() {
// Allow the visitor to give a hint if it wants.
object.visit(scope)
} else {
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 94828b4..dbedd22 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -4,11 +4,11 @@ use crate::{
higher_ranked_type,
hkt::Marker,
protocol::{
- walker::hint::{HintKnown, HintMeta},
- Visitor,
+ walker::hint::{HintMeta, Meta},
+ DynVisitor,
},
symbol::Symbol,
- DynWalker, DynWalkerAdapter, DynWalkerError, WalkerTypes,
+ DynWalkerObjSafe, DynWalkerAdapter, DynWalkerError, WalkerTypes,
};
use super::VisitResult;
@@ -39,8 +39,8 @@ pub trait Tag<'ctx, K: TagKind, E: Effect> {
fn visit<'a>(
&'a mut self,
kind: K,
- walker: DynWalker<'a, 'ctx, E>,
- ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E>;
+ walker: DynWalkerObjSafe<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E>;
}
pub struct TagProto<K: TagKind, E: Effect>(Marker<(K, E)>);
@@ -63,8 +63,12 @@ higher_ranked_type! {
}
}
+pub struct TagKnown {
+ pub kind_available: Option<bool>,
+}
+
higher_ranked_type! {
- impl HintKnown {
+ impl Meta {
impl['a, 'ctx] type T['a, 'ctx] for TagKnown =
TagKnown;
@@ -73,18 +77,32 @@ higher_ranked_type! {
}
}
-pub struct TagKnown {
- pub kind_available: Option<bool>,
-}
-
pub struct TagHint<K> {
pub kind: K,
}
+higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx, K] type T['a, 'ctx] for TagHint<K> =
+ TagHint<K>
+ where {
+ K: Send + Sync
+ };
+
+ impl['a, 'ctx, K] type HigherRanked['a, 'ctx] for TagHint<K> =
+ TagHint<K>
+ where {
+ K: Send + Sync
+ };
+ }
+}
+
impl<K: TagKind, E: Effect> HintMeta for TagProto<K, E> {
type Known = TagKnown;
type Hint = TagHint<K>;
+
+ type Effect = E;
}
#[derive(Debug)]
@@ -139,7 +157,7 @@ impl<E> TagError<E> {
pub fn visit_tag<'a, 'ctx: 'a, K: TagKind, E: Effect, W: crate::Walker<'ctx, E> + 'a>(
kind: K,
- visitor: Visitor<'a, 'ctx>,
+ mut visitor: DynVisitor<'a, 'ctx>,
walker: W,
) -> Future<'a, Result<VisitResult<W>, TagError<W::Error>>, E>
where
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index b2ae696..8e902ab 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -8,8 +8,8 @@ use crate::{
higher_ranked_type,
hkt::Marker,
protocol::{
- walker::hint::{HintKnown, HintMeta},
- Visitor,
+ walker::hint::{HintMeta, Meta},
+ DynVisitor,
},
};
@@ -69,7 +69,7 @@ pub struct ValueKnown<'a, T: ?Sized> {
pub struct ValueKnownHrt<T: ?Sized>(Marker<T>);
higher_ranked_type! {
- impl HintKnown {
+ impl Meta {
impl['a, 'ctx, T] type T['a, 'ctx] for ValueKnownHrt<T> =
ValueKnown<'a, TypeName::T<'a, 'ctx, T>>
where {
@@ -89,16 +89,18 @@ impl<T: TypeName::MemberType, E: Effect> HintMeta for ValueProto<T, E> {
type Known = ValueKnownHrt<T>;
type Hint = ();
+
+ type Effect = E;
}
pub fn visit_value<'a, 'ctx, T: Send + TypeName::LowerType<'a, 'ctx>, E: Effect>(
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
value: T,
) -> Future<'a, VisitResult<T>, E>
where
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.0.upcast_mut::<ValueProto<TypeName::HigherRanked<'a, 'ctx, T>, E>>()
{
// Allow the visitor to give a hint if it wants.
object.visit(value)
@@ -107,168 +109,3 @@ where
E::ready(VisitResult::Skipped(value))
}
}
-
-// #[cfg(test)]
-// mod test {
-// use core::marker::PhantomData;
-//
-// use crate::{
-// any::{AnyTrait, BorrowedMutStatic, BorrowedStatic, OwnedStatic},
-// any_trait,
-// effect::{BlockOn, Blocking, Spin},
-// };
-//
-// use super::*;
-//
-// #[test]
-// fn visit() {
-// struct Visitor<E>(Option<i32>, PhantomData<fn() -> E>);
-//
-// impl<'ctx, E> Value<'ctx, OwnedStatic<i32>, E> for Visitor<E>
-// where
-// E: Effect,
-// {
-// fn visit<'a>(&'a mut self, OwnedStatic(value): OwnedStatic<i32>) -> Future<'a, Flow, E>
-// where
-// 'ctx: 'a,
-// {
-// E::wrap(async move {
-// self.0 = Some(value);
-// Flow::Continue
-// })
-// }
-// }
-//
-// impl<'ctx, E> Value<'ctx, BorrowedStatic<'ctx, i32>, E> for Visitor<E>
-// where
-// E: Effect,
-// {
-// fn visit<'a>(
-// &'a mut self,
-// BorrowedStatic(value): BorrowedStatic<'ctx, i32>,
-// ) -> Future<'a, Flow, E>
-// where
-// 'ctx: 'a,
-// {
-// E::wrap(async {
-// self.0 = Some(*value);
-// Flow::Continue
-// })
-// }
-// }
-//
-// any_trait! {
-// impl['ctx, E] Visitor<E> = [
-// DynValue<'ctx, OwnedStatic<i32>, E>,
-// DynValue<'ctx, BorrowedStatic<'ctx, i32>, E>,
-// ] where E: Effect,
-// }
-//
-// let mut v = Visitor::<Blocking>(None, PhantomData);
-// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v;
-// let _ = Spin::block_on(
-// object
-// .upcast_mut::<DynValue<'_, OwnedStatic<i32>, Blocking>>()
-// .unwrap()
-// .visit(OwnedStatic(42)),
-// );
-//
-// assert_eq!(v.0, Some(42));
-//
-// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v;
-// let _ = Spin::block_on(
-// object
-// .upcast_mut::<DynValue<'_, BorrowedStatic<'_, i32>, Blocking>>()
-// .unwrap()
-// .visit(BorrowedStatic(&101)),
-// );
-//
-// assert_eq!(v.0, Some(101));
-// }
-//
-// #[test]
-// fn visit_borrowed() {
-// struct Visitor<'ctx, E>(Option<&'ctx mut String>, PhantomData<fn() -> E>);
-//
-// impl<'ctx, E> Value<'ctx, BorrowedMutStatic<'ctx, String>, E> for Visitor<'ctx, E>
-// where
-// E: Effect,
-// {
-// fn visit<'a>(
-// &'a mut self,
-// BorrowedMutStatic(value): BorrowedMutStatic<'ctx, String>,
-// ) -> Future<'a, Flow, E>
-// where
-// 'ctx: 'a,
-// {
-// E::wrap(async {
-// self.0 = Some(value);
-//
-// Flow::Continue
-// })
-// }
-// }
-//
-// any_trait! {
-// impl['ctx, E] Visitor<'ctx, E> = [
-// DynValue<'ctx, BorrowedMutStatic<'ctx, String>, E>,
-// ] where E: Effect
-// }
-//
-// let mut v = Visitor::<Blocking>(None, PhantomData);
-//
-// let mut y = String::from("abc");
-// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v;
-// let _ = Spin::block_on(
-// object
-// .upcast_mut::<DynValue<'_, BorrowedMutStatic<'_, _>, Blocking>>()
-// .unwrap()
-// .visit(BorrowedMutStatic(&mut y)),
-// );
-//
-// v.0.unwrap().push_str("def");
-// assert_eq!(y, "abcdef");
-// }
-//
-// #[test]
-// fn visit_borrowed_unsized() {
-// struct Visitor<'ctx, E>(Option<&'ctx str>, PhantomData<fn() -> E>);
-//
-// impl<'ctx, E> Value<'ctx, BorrowedStatic<'ctx, str>, E> for Visitor<'ctx, E>
-// where
-// E: Effect,
-// {
-// fn visit<'a>(
-// &'a mut self,
-// BorrowedStatic(value): BorrowedStatic<'ctx, str>,
-// ) -> Future<'a, Flow, E>
-// where
-// 'ctx: 'a,
-// {
-// E::wrap(async {
-// self.0 = Some(value);
-// Flow::Continue
-// })
-// }
-// }
-//
-// any_trait! {
-// impl['ctx, E] Visitor<'ctx, E> = [
-// DynValue<'ctx, BorrowedStatic<'ctx, str>, E>,
-// ] where E: Effect
-// }
-//
-// let mut v = Visitor::<Blocking>(None, PhantomData);
-//
-// let y = String::from("abc");
-// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v;
-// let _ = Spin::block_on(
-// object
-// .upcast_mut::<DynValue<'_, BorrowedStatic<'_, str>, Blocking>>()
-// .unwrap()
-// .visit(BorrowedStatic(&y)),
-// );
-//
-// assert_eq!(v.0, Some("abc"));
-// }
-// }
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 9bb35e6..9253264 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -9,12 +9,12 @@ use crate::{
effect::{Effect, Future},
higher_ranked_trait, higher_ranked_type,
hkt::Marker,
- protocol::Visitor,
+ protocol::DynVisitor,
Flow,
};
higher_ranked_trait! {
- pub type class HintKnown for<'a, 'ctx> {
+ pub type class Meta for<'a, 'ctx> {
type Bound = &'a &'ctx ();
type T: { Send + Sized } where { 'ctx: 'a };
@@ -23,6 +23,13 @@ higher_ranked_trait! {
}
}
+higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for () = ();
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for () = ();
+ }
+}
+
/// Meta information for the hint.
///
/// This gives the visitor more information to work from when selecting a hint.
@@ -31,115 +38,49 @@ pub trait HintMeta: Send + Sync + 'static {
///
/// This should be information easy to get without changing the state of the walker
/// in an irreversible way.
- type Known: HintKnown::MemberType;
+ type Known: Meta::MemberType;
/// Extra information the visitor can give to the walker about what it is expecting.
- type Hint;
+ type Hint: Meta::MemberType;
+
+ type Effect: Effect;
}
-pub type Known<'a, 'ctx, Protocol> = HintKnown::T<'a, 'ctx, <Protocol as HintMeta>::Known>;
+pub type MetaKnown<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Known>;
+pub type MetaHint<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Hint>;
/// Object implementing the [`Hint`] protocol.
-pub trait Hint<'ctx, Protocol: ?Sized + HintMeta, E: Effect> {
+pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
/// 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>::Hint,
- ) -> Future<'a, Flow, E>;
+ visitor: DynVisitor<'a, 'ctx>,
+ hint: MetaHint<'a, 'ctx, Protocol>,
+ ) -> Future<'a, Flow, Protocol::Effect>;
/// Ask the walker for information about it's support of the protocol.
fn known<'a>(
&'a mut self,
- hint: &'a <Protocol as HintMeta>::Hint,
- ) -> Future<'a, Result<Known<'a, 'ctx, Protocol>, ()>, E>;
+ hint: &'a MetaHint<'a, 'ctx, Protocol>,
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, Protocol>, ()>, Protocol::Effect>;
}
-pub struct HintProto<Protocol: ?Sized, E: Effect>(Marker<(*const Protocol, E)>);
+pub struct HintProto<Protocol: ?Sized>(Marker<Protocol>);
higher_ranked_type! {
impl TypeName {
- impl['a, 'ctx, Protocol, E] type T['a, 'ctx] for HintProto<Protocol, E> =
- dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a
+ impl['a, 'ctx, Protocol] type T['a, 'ctx] for HintProto<Protocol> =
+ dyn Hint<'ctx, Protocol> + Send + Sync + 'a
where {
Protocol: 'static,
- E: Effect
};
- impl['a, 'ctx, Protocol, E] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a =
- HintProto<Protocol, E>
+ impl['a, 'ctx, Protocol] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol> + Send + Sync + 'a =
+ HintProto<Protocol>
where {
Protocol: 'static,
- E: Effect,
};
}
}
-
-// #[cfg(test)]
-// mod test {
-// use crate::{
-// effect::{BlockOn, Blocking, Spin},
-// };
-//
-// use super::*;
-//
-// #[test]
-// fn demo() {
-// struct X<'ctx>(&'ctx mut i32);
-//
-// #[derive(Debug)]
-// struct Y;
-//
-// bijective_higher_ranked_type! {
-// type DynY['ctx][]: WithContextLt['ctx][] for<'a> (Y)
-// }
-//
-// bijective_higher_ranked_type! {
-// type [][]: TypeName[][] for<'ctx> (DynY<'ctx>)
-// }
-//
-// impl<'ctx, E: Effect<'ctx>> Hint<'ctx, DynY<'ctx>, E> for X<'ctx> {
-// fn hint<'a>(
-// &'a mut self,
-// _visitor: Visitor<'a, 'ctx>,
-// _hint: <DynY<'ctx> as HintMeta<'ctx>>::Hint,
-// ) -> Future<'a, 'ctx, Flow, E> {
-// todo!()
-// }
-//
-// fn known<'a>(
-// &'a mut self,
-// _hint: &'a <DynY<'ctx> as HintMeta<'ctx>>::Hint,
-// ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynY<'ctx>>, ()>, E> {
-// E::ready(Ok(&mut *self.0))
-// }
-// }
-//
-// higher_ranked_type! {
-// type KnownHkt['ctx]: (AnySend) = for<'lt> &'lt mut i32
-// }
-//
-// impl<'ctx> HintMeta<'ctx> for DynY<'ctx> {
-// type Known = KnownHkt<'ctx>;
-//
-// type Hint = ();
-// }
-//
-// let mut z = 42;
-// let mut x = X(&mut z);
-// let y: &mut WithContextLt::T<'_, '_, DynHint<'_, DynY<'_>, Blocking>> = &mut x;
-//
-// fn id<'a, 'ctx, T: ?Sized + TypeName::LowerType<'ctx>>(_x: &WithContextLt::T<'a, 'ctx, T>) {
-// }
-// id::<DynHint<'_, DynY<'_>, Blocking>>(y);
-//
-// let x = Spin::block_on(y.known(&()));
-// match x {
-// Ok(value) => *value += 1,
-// Err(_) => todo!(),
-// }
-// assert_eq!(z, 43);
-// }
-// }
diff --git a/src/transform.rs b/src/transform.rs
index 64aea20..edfa92a 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -1,7 +1,8 @@
use crate::{
build::Builder,
effect::{Effect, Future},
- Walker,
+ hkt::Marker,
+ Walk, Walker, WalkerTypes,
};
#[inline]
@@ -23,3 +24,85 @@ pub fn transform<'a, 'ctx, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a, E:
(builder_result, walker_result)
})
}
+
+/// For use in a lens.
+pub struct Projection<T, B, U, M> {
+ value: T,
+ builder: B,
+ _marker: Marker<(U, M)>,
+}
+
+impl<T, B, U: Send + Sync, M> Projection<T, B, U, M> {
+ pub fn project_ref<'a, E: Effect>(
+ &'a self,
+ ) -> Future<
+ 'a,
+ (
+ Result<&'a U, B::Error>,
+ Result<<&'a T as WalkerTypes>::Output, <&'a T as WalkerTypes>::Error>,
+ ),
+ E,
+ >
+ where
+ &'a T: Walk<'a, M, E>,
+ B: Clone + Builder<'a, E, Value = &'a U>,
+ {
+ let walker = self.value.into_walker();
+ let mut builder = self.builder.clone();
+
+ E::wrap(async {
+ let result = walker.walk(builder.as_visitor()).await;
+
+ (builder.build().await, result)
+ })
+ }
+
+ pub fn project_mut<'a, E: Effect>(
+ &'a mut self,
+ ) -> Future<
+ 'a,
+ (
+ Result<&'a mut U, B::Error>,
+ Result<<&'a mut T as WalkerTypes>::Output, <&'a mut T as WalkerTypes>::Error>,
+ ),
+ E,
+ >
+ where
+ &'a mut T: Walk<'a, M, E>,
+ B: Clone + Builder<'a, E, Value = &'a mut U>,
+ {
+ let walker = self.value.into_walker();
+ let mut builder = self.builder.clone();
+
+ E::wrap(async {
+ let result = walker.walk(builder.as_visitor()).await;
+
+ (builder.build().await, result)
+ })
+ }
+
+ pub fn project<'a, E: Effect>(
+ self,
+ ) -> Future<
+ 'a,
+ (
+ Result<U, B::Error>,
+ Result<<T as WalkerTypes>::Output, <T as WalkerTypes>::Error>,
+ ),
+ E,
+ >
+ where
+ T: Walk<'a, M, E> + 'a,
+ M: 'a,
+ B: Clone + Builder<'a, E, Value = U> + 'a,
+ {
+ let walker = self.value.into_walker();
+ let mut builder = self.builder.clone();
+
+ E::wrap(async {
+ let result = walker.walk(builder.as_visitor()).await;
+
+ (builder.build().await, result)
+ })
+ }
+}
diff --git a/src/walk.rs b/src/walk.rs
index 5bdd5ec..349a63d 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -2,7 +2,7 @@ pub mod walkers;
use crate::{
effect::{Effect, Future},
- protocol::Visitor,
+ protocol::DynVisitor,
Flow,
};
@@ -16,12 +16,12 @@ pub trait Walk<'ctx, M, E: Effect>: WalkerTypes + Sized {
}
pub trait WalkerTypes {
- type Error: Send;
+ type Error: Send + Sync;
/// An arbitrary type the walker is left with after walking.
///
/// Its recommended that this is `Self` if the walker is repeatable.
- type Output: Send;
+ type Output: Send + Sync;
}
/// Walker for a type.
@@ -33,25 +33,25 @@ pub trait WalkerTypes {
/// - Call [From::from()] with a value to be walked to make a walker.
/// - Call [Self::walk()] to walk the value. Data will be sent to the provided
/// visitor.
-pub trait Walker<'ctx, E: Effect>: WalkerTypes + Send {
+pub trait Walker<'ctx, E: Effect>: WalkerTypes + Send + Sync {
/// Walk the value.
///
/// The walker should send data to the `visitor` as it walks the value.
fn walk<'a>(
self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a;
}
pub trait WalkerObjSafe<'ctx, E: Effect>: Send {
- fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>
+ fn walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E>
where
Self: 'a;
}
-pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a);
+pub type DynWalkerObjSafe<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a);
enum DynWalkerState<W: WalkerTypes> {
Walking,
@@ -103,7 +103,7 @@ impl<W: WalkerTypes> DynWalkerAdapter<W> {
}
impl<'ctx, W: Walker<'ctx, E>, E: Effect> WalkerObjSafe<'ctx, E> for DynWalkerAdapter<W> {
- fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>
+ fn walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E>
where
Self: 'a,
{
diff --git a/src/walk/walkers/core/key_value.rs b/src/walk/walkers/core/key_value.rs
index 85a15a3..8e14a1c 100644
--- a/src/walk/walkers/core/key_value.rs
+++ b/src/walk/walkers/core/key_value.rs
@@ -3,7 +3,7 @@ use crate::{
never::Never,
protocol::{
visitor::{visit_tag, TagConst, TagError, TagKind, VisitResult},
- Visitor,
+ DynVisitor,
},
walkers::core::noop::NoopWalker,
Flow, WalkerTypes, TAG_KEY, TAG_KEY_VALUE, TAG_VALUE,
@@ -55,17 +55,17 @@ where
{
fn walk<'a>(
self,
- visitor: Visitor<'a, 'ctx>,
+ mut visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
{
E::wrap(async move {
- match visit_tag::<T, E, _>(self.tag, visitor, NoopWalker::new()).await {
+ match visit_tag::<T, E, _>(self.tag, visitor.cast(), NoopWalker::new()).await {
Ok(VisitResult::Skipped(_)) => {
match visit_tag::<TagConst<{ TAG_KEY_VALUE.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
NoopWalker::new(),
)
.await
@@ -82,7 +82,7 @@ where
match visit_tag::<TagConst<{ TAG_KEY.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
self.key_walker,
)
.await
@@ -94,7 +94,7 @@ where
match visit_tag::<TagConst<{ TAG_VALUE.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
self.value_walker,
)
.await
diff --git a/src/walk/walkers/core/noop.rs b/src/walk/walkers/core/noop.rs
index 8bb05cb..7468016 100644
--- a/src/walk/walkers/core/noop.rs
+++ b/src/walk/walkers/core/noop.rs
@@ -1,7 +1,7 @@
use crate::{
effect::{Effect, Future},
never::Never,
- protocol::Visitor,
+ protocol::DynVisitor,
WalkerTypes,
};
@@ -27,7 +27,7 @@ impl WalkerTypes for NoopWalker {
impl<'ctx, E: Effect> crate::Walker<'ctx, E> for NoopWalker {
fn walk<'a>(
self,
- _visitor: Visitor<'a, 'ctx>,
+ _visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index 93e8bba..8fe0ce0 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -12,10 +12,7 @@ use crate::{
RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto,
SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown,
ValueProto, VisitResult,
- },
- walker::hint::{Hint, Known},
- walker::hint::{HintMeta, HintProto},
- Visitor,
+ }, walker::hint::{Hint, MetaKnown}, walker::hint::{HintMeta, HintProto, MetaHint}, DynVisitor, DynWalker
},
Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME,
};
@@ -58,7 +55,7 @@ pub trait StructTypeInfo<'ctx, M>: 'static {
fn walk_field<'a, E: Effect>(
index: usize,
value: &'ctx Self::T,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Flow, Self::FieldError>, E>;
}
@@ -117,14 +114,14 @@ where
{
fn walk<'a>(
mut self,
- visitor: Visitor<'a, 'ctx>,
+ mut visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
{
- E::wrap(async {
+ E::wrap(async move {
// Use the recoverable walk to not duplicate the code.
- let _ = RecoverableScope::<'ctx, E>::new_walk(&mut self, visitor).await;
+ let _ = RecoverableScope::<'ctx, E>::new_walk(&mut self, visitor.cast()).await;
// Get the error if there was one.
match self.error {
@@ -137,22 +134,22 @@ where
any_trait! {
impl['ctx, T, I, M, E] StructWalker<'ctx, T, I, M, E> = [
- HintProto<RecoverableProto<E>, E>,
- HintProto<SequenceProto<E>, E>,
- HintProto<ValueProto<BorrowedStaticHrt<T>, E>, E>,
- HintProto<TagProto<TagDyn, E>, E>,
- HintProto<TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>,
- HintProto<TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>,
- HintProto<TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>,
- HintProto<TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E>,
- HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>,
+ HintProto<RecoverableProto<E>>,
+ HintProto<SequenceProto<E>>,
+ HintProto<ValueProto<BorrowedStaticHrt<T>, E>>,
+ HintProto<TagProto<TagDyn, E>>,
+ HintProto<TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>,
+ HintProto<TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>,
+ HintProto<TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>,
+ HintProto<TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>,
+ HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>,
] where
E: Effect,
T: Send + Sync + 'static,
I: StructTypeInfo<'ctx, M, T = T>
}
-impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>> for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M, T = T>,
@@ -160,7 +157,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <RecoverableProto<E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(
@@ -175,12 +172,12 @@ where
fn known<'a>(
&'a mut self,
_hint: &'a <RecoverableProto<E> as HintMeta>::Hint,
- ) -> Future<'a, Result<Known<'a, 'ctx, RecoverableProto<E>>, ()>, E> {
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, RecoverableProto<E>>, ()>, E> {
E::ready(Ok(RecoverableKnown))
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
@@ -189,8 +186,8 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
- _hint: <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint,
+ visitor: DynVisitor<'a, 'ctx>,
+ _hint: MetaHint<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>,
) -> Future<'a, Flow, E> {
E::map(
visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>(
@@ -211,10 +208,10 @@ where
fn known<'a>(
&'a mut self,
- _hint: &'a <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint,
+ _hint: &'a MetaHint<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>,
) -> Future<
'a,
- Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>,
+ Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>,
E,
> {
E::ready(Ok(TagKnown {
@@ -223,7 +220,7 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
@@ -232,7 +229,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(
@@ -255,15 +252,18 @@ where
fn known<'a>(
&'a mut self,
_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>
- {
+ ) -> Future<
+ 'a,
+ Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>,
+ E,
+ > {
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
@@ -272,7 +272,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(
@@ -291,7 +291,7 @@ where
fn known<'a>(
&'a mut self,
_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>
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, ()>, E>
{
E::ready(Ok(TagKnown {
kind_available: Some(true),
@@ -299,7 +299,7 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
@@ -308,7 +308,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(
@@ -331,15 +331,18 @@ where
fn known<'a>(
&'a mut self,
_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>
- {
+ ) -> Future<
+ 'a,
+ Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>,
+ E,
+ > {
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
@@ -348,7 +351,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(
@@ -371,15 +374,18 @@ where
fn known<'a>(
&'a mut self,
_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>
- {
+ ) -> Future<
+ 'a,
+ Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>,
+ E,
+ > {
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagDyn, E>, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagDyn, E>> for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M>,
@@ -387,38 +393,39 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
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(
+ Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>::hint(
self,
visitor,
TagHint { kind: TagConst },
)
}
crate::TAG_STRUCT => {
- Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>::hint(
+ Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>::hint(
self,
visitor,
TagHint { kind: TagConst },
)
}
- crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>::hint(
+ crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>::hint(
self,
visitor,
TagHint { kind: TagConst },
),
- crate::TAG_TYPE_NAME => Hint::<
- 'ctx,
- TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>,
- E,
- >::hint(self, visitor, TagHint { kind: TagConst }),
+ crate::TAG_TYPE_NAME => {
+ Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>::hint(
+ self,
+ visitor,
+ TagHint { kind: TagConst },
+ )
+ }
crate::TAG_FIELD_NAMES => Hint::<
'ctx,
TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>,
- E,
>::hint(self, visitor, TagHint { kind: TagConst }),
_ => E::ready(Flow::Continue),
}
@@ -427,7 +434,7 @@ where
fn known<'a>(
&'a mut self,
hint: &'a <TagProto<TagDyn, E> as HintMeta>::Hint,
- ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagDyn, E>>, ()>, E> {
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, TagProto<TagDyn, E>>, ()>, E> {
E::ready(match hint.kind {
TagDyn(crate::TAG_TYPE_ID) | TagDyn(crate::TAG_STRUCT) => Ok(TagKnown {
kind_available: Some(true),
@@ -439,14 +446,14 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>>
for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M>,
T: Send + Sync + 'static,
{
- fn hint<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> {
+ fn hint<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> {
E::map(
visit_value::<_, E>(visitor, BorrowedStatic(self.value)),
|status| match status {
@@ -464,7 +471,7 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, SequenceProto<E>, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, T, I, M, E> Hint<'ctx, SequenceProto<E>> for StructWalker<'ctx, T, I, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M, T = T>,
@@ -472,7 +479,7 @@ where
{
fn hint<'a>(
&'a mut self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
_hint: <SequenceProto<E> as HintMeta>::Hint,
) -> Future<'a, Flow, E> {
E::map(visit_sequence::<E>(visitor, self), |status| match status {
@@ -484,7 +491,7 @@ where
fn known<'a>(
&'a mut self,
_hint: &'a <SequenceProto<E> as HintMeta>::Hint,
- ) -> Future<'a, Result<Known<'a, 'ctx, SequenceProto<E>>, ()>, E> {
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, SequenceProto<E>>, ()>, E> {
let len = I::FIELDS.len();
E::ready(Ok(SequenceKnown {
@@ -504,7 +511,7 @@ where
E::ready((len, Some(len)))
}
- fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> {
+ fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> {
if self.index >= I::FIELDS.len() {
return E::ready(Flow::Done);
}
@@ -532,7 +539,7 @@ where
I: StructTypeInfo<'ctx, M, T = T>,
T: Send + Sync + 'static,
{
- fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E> {
+ fn new_walk<'a>(&'a mut self, mut visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E> {
// Reset the errors to default state.
self.error = None;
@@ -541,14 +548,14 @@ where
E::wrap(async move {
// We should check if the visitor wants something specific.
- match visit_request_hint::<E>(visitor, self).await {
+ match visit_request_hint::<E>(visitor.cast(), DynWalker(self)).await {
VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {}
VisitResult::Control(Flow::Done) => return Ok(()),
VisitResult::Control(Flow::Err) => return Err(()),
}
// Attempt to visit the value directly.
- match visit_value::<_, E>(visitor, BorrowedStatic(self.value)).await {
+ match visit_value::<_, E>(visitor.cast(), BorrowedStatic(self.value)).await {
VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {}
VisitResult::Control(Flow::Done) => return Ok(()),
VisitResult::Control(Flow::Err) => return Err(()),
@@ -563,7 +570,7 @@ where
match visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
ValueWalker::new(TypeId::of::<T>()),
)
.await
@@ -579,7 +586,7 @@ where
match visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
NoopWalker::new(),
)
.await
@@ -587,7 +594,7 @@ where
Ok(VisitResult::Skipped(_)) => {
match visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
NoopWalker::new(),
)
.await
@@ -612,7 +619,7 @@ where
match visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
ValueWalker::new(I::NAME),
)
.await
@@ -628,7 +635,7 @@ where
match visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>(
TagConst,
- visitor,
+ visitor.cast(),
StaticSliceWalker::<_, ValueWalker<&'static str>>::new(I::FIELDS),
)
.await
diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs
index a4f1cea..f20b449 100644
--- a/src/walk/walkers/core/tag.rs
+++ b/src/walk/walkers/core/tag.rs
@@ -8,8 +8,7 @@ use crate::{
protocol::{
visitor::{
visit_request_hint, visit_value, SequenceProto, SequenceScope, TagError, VisitResult,
- },
- Visitor,
+ }, DynVisitor, DynWalker
},
Flow, WalkerTypes,
};
@@ -45,24 +44,24 @@ where
{
fn walk<'a>(
mut self,
- visitor: Visitor<'a, 'ctx>,
+ mut visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
{
E::wrap(async move {
- match visit_request_hint::<E>(visitor, &mut self).await {
+ match visit_request_hint::<E>(visitor.cast(), DynWalker(&mut self)).await {
VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {}
_ => return Ok(()),
}
- match visit_value::<_, E>(visitor, OwnedStatic(self.names)).await {
+ match visit_value::<_, E>(visitor.cast(), OwnedStatic(self.names)).await {
VisitResult::Skipped(_) => {}
VisitResult::Control(Flow::Continue) => {}
_ => return Ok(()),
}
- if let Some(object) = visitor.upcast_mut::<SequenceProto<E>>() {
+ if let Some(object) = visitor.cast().upcast_mut::<SequenceProto<E>>() {
// Visit with the name. Ignore the flow because we return a result not a flow.
let _ = object.visit(&mut self).await;
}
@@ -84,7 +83,7 @@ where
T: Sync,
&'static T: Into<W>,
{
- fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> {
+ fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> {
if let Some(name) = self.names.get(self.current) {
self.current += 1;
E::wrap(async move {
diff --git a/src/walk/walkers/core/value.rs b/src/walk/walkers/core/value.rs
index b8e5b79..c33b2fe 100644
--- a/src/walk/walkers/core/value.rs
+++ b/src/walk/walkers/core/value.rs
@@ -2,7 +2,7 @@ use crate::{
any::{BorrowedStatic, OwnedStatic},
effect::{Effect, Future},
never::Never,
- protocol::{visitor::visit_value, Visitor},
+ protocol::{visitor::visit_value, DynVisitor},
WalkerTypes,
};
@@ -41,7 +41,7 @@ impl<T> WalkerTypes 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>,
+ visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
@@ -77,7 +77,7 @@ impl<'ctx, T: ?Sized + Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E>
{
fn walk<'a>(
self,
- visitor: Visitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
diff --git a/tests/common/builder.rs b/tests/common/builder.rs
index 160846a..e12b013 100644
--- a/tests/common/builder.rs
+++ b/tests/common/builder.rs
@@ -2,7 +2,7 @@ use mockall::mock;
use treaty::{
any::{indirect, AnyTrait, AnyTraitObject, TypeNameId},
effect::{Effect, Future},
- protocol::Visitor,
+ protocol::DynVisitor,
Builder, BuilderTypes,
};
@@ -17,12 +17,14 @@ mock! {
pub fn from_seed(seed: Seed) -> Self;
pub fn build(self) -> Result<Value, Error>;
- pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
- pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>;
+ pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>;
+ pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>;
}
}
-impl<Seed: Send, Value: Send, Error: Send> BuilderTypes for MockBuilder<Seed, Value, Error> {
+impl<Seed: Send + Sync, Value: Send + Sync, Error: Send + Sync> BuilderTypes
+ for MockBuilder<Seed, Value, Error>
+{
type Seed = Seed;
type Error = Error;
@@ -44,7 +46,7 @@ impl<Seed: 'static, Value: 'static, Error: 'static> MockBuilder<Seed, Value, Err
}
}
-impl<'ctx, Seed: Send, Value: Send, Error: Send, E: Effect> Builder<'ctx, E>
+impl<'ctx, Seed: Send + Sync, Value: Send + Sync, Error: Send + Sync, E: Effect> Builder<'ctx, E>
for MockBuilder<Seed, Value, Error>
{
fn from_seed<'a>(seed: Self::Seed) -> Future<'a, Self, E>
@@ -61,8 +63,8 @@ impl<'ctx, Seed: Send, Value: Send, Error: Send, E: Effect> Builder<'ctx, E>
E::ready(self.build())
}
- fn as_visitor(&mut self) -> Visitor<'_, 'ctx> {
- self
+ fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
+ DynVisitor(self)
}
}
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index 8b9fb03..bad703e 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -11,6 +11,7 @@ use std::{
pub mod builder;
pub mod protocol;
+pub mod walker;
pub struct StaticTypeMap {
map: OnceLock<RwLock<HashMap<TypeId, &'static (dyn Any + Send + Sync)>>>,
diff --git a/tests/common/protocol.rs b/tests/common/protocol.rs
index 148a458..ab619e0 100644
--- a/tests/common/protocol.rs
+++ b/tests/common/protocol.rs
@@ -1,3 +1,5 @@
pub mod hint;
+pub mod request_hint;
+pub mod sequence;
pub mod tag;
pub mod visitor;
diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs
index bcc2a02..07c7c41 100644
--- a/tests/common/protocol/hint.rs
+++ b/tests/common/protocol/hint.rs
@@ -3,44 +3,43 @@ use treaty::{
any::{any_trait, TypeName},
effect::{Effect, Future},
protocol::{
- walker::hint::{Hint, HintMeta, HintProto, Known},
- Visitor,
+ walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown},
+ DynVisitor,
},
Flow,
};
pub type KnownFactory<P> =
- for<'a, 'ctx> fn(&'ctx (), &'a <P as HintMeta>::Hint) -> Result<Known<'a, 'ctx, P>, ()>;
+ for<'a, 'ctx> fn(&'ctx (), &'a MetaHint<'a, 'ctx, P>) -> Result<MetaKnown<'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 HintWalker<P: HintMeta> {
+ pub fn hint<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>, hint: MetaHint<'a, 'ctx, P>) -> Flow;
pub fn known(&self) -> KnownFactory<P>;
}
}
any_trait! {
- impl['ctx, P, E] MockHintVisitor<P, E> = [
- HintProto<P, E>
+ impl['ctx, P] MockHintWalker<P> = [
+ HintProto<P>
] where
P: HintMeta,
- E: Effect,
}
-impl<'ctx, P: HintMeta, E: Effect> Hint<'ctx, P, E> for MockHintVisitor<P, E> {
+impl<'ctx, P: HintMeta> Hint<'ctx, P> for MockHintWalker<P> {
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))
+ visitor: DynVisitor<'a, 'ctx>,
+ hint: MetaHint<'a, 'ctx, P>,
+ ) -> Future<'a, Flow, P::Effect> {
+ P::Effect::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))
+ hint: &'a MetaHint<'a, 'ctx, P>,
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, P>, ()>, P::Effect> {
+ P::Effect::ready(Self::known(self)(&(), hint))
}
}
diff --git a/tests/common/protocol/request_hint.rs b/tests/common/protocol/request_hint.rs
new file mode 100644
index 0000000..be203b3
--- /dev/null
+++ b/tests/common/protocol/request_hint.rs
@@ -0,0 +1,33 @@
+use mockall::mock;
+use treaty::{
+ any::{any_trait, TypeName},
+ effect::{Effect, Future},
+ protocol::visitor::{RequestHint, RequestHintProto, Value, ValueProto, VisitResult},
+ protocol::DynWalker,
+ Flow,
+};
+
+pub type RequestHintFactory =
+ for<'a, 'ctx> fn(&'ctx (), DynWalker<'a, 'ctx>) -> VisitResult<DynWalker<'a, 'ctx>>;
+
+mock! {
+ pub RequestHintVisitor<E> {
+ pub fn request_hint(&mut self) -> RequestHintFactory;
+ }
+}
+
+any_trait! {
+ impl['ctx, E] MockRequestHintVisitor<E> = [
+ RequestHintProto<E>
+ ] where
+ E: Effect,
+}
+
+impl<'ctx, E: Effect> RequestHint<'ctx, E> for MockRequestHintVisitor<E> {
+ fn request_hint<'a>(
+ &'a mut self,
+ walker: DynWalker<'a, 'ctx>,
+ ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ E::ready(self.request_hint()(&(), walker))
+ }
+}
diff --git a/tests/common/protocol/sequence.rs b/tests/common/protocol/sequence.rs
new file mode 100644
index 0000000..ff4249f
--- /dev/null
+++ b/tests/common/protocol/sequence.rs
@@ -0,0 +1,58 @@
+use mockall::mock;
+use treaty::{
+ any::{any_trait, TypeName},
+ effect::{Effect, Future},
+ protocol::DynWalker,
+ protocol::{
+ visitor::{
+ DynSequenceScope, RequestHint, RequestHintProto, Sequence, SequenceProto,
+ SequenceScope, Value, ValueProto, VisitResult,
+ },
+ DynVisitor,
+ },
+ Flow,
+};
+
+pub type SequenceScopeFactory<E> = for<'a, 'ctx> fn(
+ &'ctx (),
+ DynSequenceScope<'a, 'ctx, E>,
+) -> VisitResult<DynSequenceScope<'a, 'ctx, E>>;
+
+mock! {
+ pub SequenceVisitor<E> {
+ pub fn visit(&mut self) -> SequenceScopeFactory<E>;
+ }
+}
+
+any_trait! {
+ impl['ctx, E] MockSequenceVisitor<E> = [
+ SequenceProto<E>
+ ] where
+ E: Effect,
+}
+
+impl<'ctx, E: Effect> Sequence<'ctx, E> for MockSequenceVisitor<E> {
+ fn visit<'a>(
+ &'a mut self,
+ scope: DynSequenceScope<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
+ E::ready(self.visit()(&(), scope))
+ }
+}
+
+mock! {
+ pub SequenceScopeVisitor<E> {
+ pub fn size_hint(&mut self) -> (usize, Option<usize>);
+ pub fn next<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Flow;
+ }
+}
+
+impl<'ctx, E: Effect> SequenceScope<'ctx, E> for MockSequenceScopeVisitor<E> {
+ fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E> {
+ E::ready(self.size_hint())
+ }
+
+ fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> {
+ E::ready(self.next(visitor))
+ }
+}
diff --git a/tests/common/protocol/tag.rs b/tests/common/protocol/tag.rs
index 7bc152a..581cced 100644
--- a/tests/common/protocol/tag.rs
+++ b/tests/common/protocol/tag.rs
@@ -3,12 +3,12 @@ use treaty::{
any::any_trait,
effect::{Effect, Future},
protocol::visitor::{Tag, TagKind, TagProto, VisitResult},
- DynWalker,
+ DynWalkerObjSafe,
};
mock! {
pub TagVisitor<K: TagKind, E> {
- pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalker<'a, 'ctx, E>) -> VisitResult<()>;
+ pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalkerObjSafe<'a, 'ctx, E>) -> VisitResult<()>;
}
}
@@ -24,8 +24,8 @@ impl<'ctx, K: TagKind, E: Effect> Tag<'ctx, K, E> for MockTagVisitor<K, E> {
fn visit<'a>(
&'a mut self,
kind: K,
- walker: DynWalker<'a, 'ctx, E>,
- ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E> {
+ walker: DynWalkerObjSafe<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> {
E::ready(match self.visit(kind, walker) {
VisitResult::Skipped(_) => VisitResult::Skipped(walker),
VisitResult::Control(flow) => VisitResult::Control(flow),
diff --git a/tests/common/walker.rs b/tests/common/walker.rs
new file mode 100644
index 0000000..b1064f6
--- /dev/null
+++ b/tests/common/walker.rs
@@ -0,0 +1,57 @@
+use mockall::mock;
+use treaty::{
+ any::{indirect, AnyTrait, AnyTraitObject, TypeNameId},
+ effect::{Effect, Future},
+ protocol::DynVisitor,
+ Builder, BuilderTypes, Walker, WalkerTypes,
+};
+
+mock! {
+ pub Walker<Output, Error> {
+ pub fn walk<'a, 'ctx>(self, visitor: DynVisitor<'a, 'ctx>) -> Result<Output, Error>;
+
+ pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>;
+ pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>;
+ }
+}
+
+impl<Output: Send + Sync, Error: Send + Sync> WalkerTypes for MockWalker<Output, Error> {
+ type Error = Error;
+
+ type Output = Output;
+}
+
+impl<'ctx, Output: Send + Sync, Error: Send + Sync, E: Effect> Walker<'ctx, E>
+ for MockWalker<Output, Error>
+{
+ fn walk<'a>(
+ self,
+ visitor: DynVisitor<'a, 'ctx>,
+ ) -> Future<'a, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'a,
+ {
+ E::ready(self.walk(visitor))
+ }
+}
+
+impl<'ctx, Output, Error> AnyTrait<'ctx> for MockWalker<Output, Error> {
+ fn upcast_to_id<'a>(&'a self, id: TypeNameId) -> Option<AnyTraitObject<'a, 'ctx, indirect::Ref>>
+ where
+ 'ctx: 'a,
+ {
+ self.traits(id).as_ref().and_then(|t| t.upcast_to_id(id))
+ }
+
+ fn upcast_to_id_mut<'a>(
+ &'a mut self,
+ id: TypeNameId,
+ ) -> Option<AnyTraitObject<'a, 'ctx, indirect::Mut>>
+ where
+ 'ctx: 'a,
+ {
+ self.traits_mut(id)
+ .as_mut()
+ .and_then(|t| t.upcast_to_id_mut(id))
+ }
+}
diff --git a/tests/protocol_visitor_request_hint.rs b/tests/protocol_visitor_request_hint.rs
new file mode 100644
index 0000000..234d64f
--- /dev/null
+++ b/tests/protocol_visitor_request_hint.rs
@@ -0,0 +1,93 @@
+use std::any::TypeId;
+
+use common::{
+ protocol::{
+ hint::MockHintWalker,
+ request_hint::{MockRequestHintVisitor, RequestHintFactory},
+ },
+ walker::MockWalker,
+};
+use mockall::predicate::eq;
+use treaty::{
+ any::{OwnedStatic, TypeNameId},
+ effect::Blocking,
+ protocol::{
+ visitor::{RequestHint, RequestHintProto, ValueKnown, ValueProto, VisitResult},
+ walker::hint::HintProto,
+ },
+ Flow,
+};
+
+use crate::common::protocol::hint::KnownFactory;
+
+mod common;
+
+#[test]
+fn hints_can_be_requested() {
+ let mut mock = MockRequestHintVisitor::<Blocking>::new();
+
+ // We will request a hint from the visitor.
+ mock.expect_request_hint().once().return_const(
+ (|_, walker| {
+ // Lookup the value protocol on the walker.
+ let obj = walker
+ .upcast_mut::<HintProto<ValueProto<OwnedStatic<i32>, Blocking>>>()
+ .unwrap();
+
+ // Get the known for the value protocol.
+ assert_eq!(
+ obj.known(&()).into_inner(),
+ Ok(ValueKnown {
+ preview: Some(&OwnedStatic(42))
+ })
+ );
+
+ // We are done.
+ VisitResult::Control(Flow::Done)
+ }) as RequestHintFactory,
+ );
+
+ // This mock becomes the visitor.
+ let visitor: &mut dyn RequestHint<Blocking> = &mut mock;
+
+ let mut mock = MockWalker::<(), ()>::new();
+
+ // The visitor will lookup the value protocol on the walker.
+ mock.expect_traits_mut()
+ .once()
+ .with(eq(TypeNameId::of::<
+ HintProto<ValueProto<OwnedStatic<i32>, Blocking>>,
+ >()))
+ .returning(|_id| {
+ let mut mock = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new();
+
+ // Expect to give a known for the value protocol to the visitor.
+ mock.expect_known().once().return_const(
+ (|_, ()| {
+ Ok(ValueKnown {
+ preview: Some(&OwnedStatic(42)),
+ })
+ }) as KnownFactory<ValueProto<OwnedStatic<i32>, Blocking>>,
+ );
+
+ Some(Box::new(mock))
+ });
+
+ // Request a hint from the visitor.
+ assert!(matches!(
+ visitor.request_hint(&mut mock).into_inner(),
+ VisitResult::Control(Flow::Done)
+ ));
+}
+
+#[test]
+fn request_hint_proto() {
+ // The type id of the higher ranked type.
+ let id = TypeId::of::<RequestHintProto<Blocking>>();
+
+ // The type id for the lifetime containing value protocol trait object.
+ let name_id = TypeNameId::of_lower::<dyn RequestHint<Blocking> + Send + Sync>();
+
+ // They should be the same.
+ assert_eq!(id, name_id.into_type_id());
+}
diff --git a/tests/protocol_visitor_sequence.rs b/tests/protocol_visitor_sequence.rs
new file mode 100644
index 0000000..52433dc
--- /dev/null
+++ b/tests/protocol_visitor_sequence.rs
@@ -0,0 +1,76 @@
+use std::any::TypeId;
+
+use common::protocol::sequence::{
+ MockSequenceScopeVisitor, MockSequenceVisitor, SequenceScopeFactory,
+};
+use treaty::{
+ any::{OwnedStatic, TypeNameId},
+ effect::Blocking,
+ protocol::{visitor::{Sequence, SequenceProto, ValueProto, VisitResult}, DynVisitor},
+ Flow,
+};
+
+use crate::common::builder::MockBuilder;
+
+mod common;
+
+#[test]
+fn sequence_has_scope_with_size_hint_and_next() {
+ let mut mock = MockSequenceVisitor::<Blocking>::new();
+
+ // Expect a visit with the sequence protocol.
+ mock.expect_visit().once().return_const(
+ (|(), scope| {
+ // Get the size hint from the sequence scope.
+ assert_eq!(scope.size_hint().into_inner(), (1, Some(1)));
+
+ let mut visitor = MockBuilder::<(), (), ()>::new();
+
+ // Expect the walker to lookup a trait.
+ visitor.expect_traits().once().return_const(None);
+
+ // Get the next item in the sequence from the walker.
+ scope.next(DynVisitor(&mut visitor));
+
+ // We are done.
+ VisitResult::Control(Flow::Done)
+ }) as SequenceScopeFactory<Blocking>,
+ );
+
+ // Everything goes throw the sequence protocol trait.
+ let visitor: &mut dyn Sequence<Blocking> = &mut mock;
+
+ let mut scope = MockSequenceScopeVisitor::<Blocking>::new();
+
+ // Expect a size hint to be asked for.
+ scope.expect_size_hint().once().return_const((1, Some(1)));
+
+ // Expect that one element is gotten from the sequence.
+ scope.expect_next().once().returning(|visitor| {
+ // Attempt to lookup a trait on the visitor.
+ assert!(visitor
+ .upcast::<ValueProto<OwnedStatic<i32>, Blocking>>()
+ .is_none());
+
+ // We are done.
+ Flow::Done
+ });
+
+ // Visit a sequence.
+ assert!(matches!(
+ visitor.visit(&mut scope).into_inner(),
+ VisitResult::Control(Flow::Done)
+ ));
+}
+
+#[test]
+fn sequence_proto() {
+ // The type id of the higher ranked type.
+ let id = TypeId::of::<SequenceProto<Blocking>>();
+
+ // The type id for the lifetime containing value protocol trait object.
+ let name_id = TypeNameId::of_lower::<dyn Sequence<Blocking> + Send + Sync>();
+
+ // They should be the same.
+ assert_eq!(id, name_id.into_type_id());
+}
diff --git a/tests/protocol_visitor_tag.rs b/tests/protocol_visitor_tag.rs
new file mode 100644
index 0000000..9e92ff6
--- /dev/null
+++ b/tests/protocol_visitor_tag.rs
@@ -0,0 +1,44 @@
+use common::protocol::tag::MockTagVisitor;
+use treaty::{
+ effect::Blocking,
+ protocol::visitor::{Tag, TagDyn, VisitResult},
+ symbol::Symbol,
+ DynWalkerAdapter, Flow,
+};
+
+use crate::common::walker::MockWalker;
+
+mod common;
+
+#[test]
+fn demo() {
+ let mut mock = MockTagVisitor::<TagDyn, Blocking>::new();
+
+ mock.expect_visit()
+ .once()
+ .returning(|TagDyn(kind), walker| {
+ assert_eq!(kind, Symbol::new("test"));
+
+ VisitResult::Control(Flow::Done)
+ });
+
+ let visitor: &mut dyn Tag<TagDyn, Blocking> = &mut mock;
+
+ let mut walker = MockWalker::<(), ()>::new();
+
+ walker.expect_walk()
+ .once()
+ .returning(|visitor| {
+
+ Ok(())
+ });
+
+ let mut walker = DynWalkerAdapter::new(walker);
+
+ assert!(matches!(
+ visitor
+ .visit(TagDyn(Symbol::new("test")), &mut walker)
+ .into_inner(),
+ VisitResult::Control(Flow::Done)
+ ));
+}
diff --git a/tests/protocol_visitor_value.rs b/tests/protocol_visitor_value.rs
index ff17fc4..8ca591c 100644
--- a/tests/protocol_visitor_value.rs
+++ b/tests/protocol_visitor_value.rs
@@ -1,19 +1,18 @@
use std::any::TypeId;
use common::protocol::{
- hint::{KnownFactory, MockHintVisitor},
+ hint::{KnownFactory, MockHintWalker},
visitor::MockValueVisitor,
};
use mockall::predicate::eq;
use treaty::{
any::{
- BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic,
+ AnyTrait, BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic,
TempBorrowedMutStaticHrt, TypeNameId,
},
effect::Blocking,
protocol::{
- visitor::{Value, ValueKnown, ValueProto, VisitResult},
- walker::hint::Hint,
+ visitor::{visit_value, Value, ValueKnown, ValueProto, VisitResult}, walker::hint::Hint, DynVisitor
},
Flow,
};
@@ -33,7 +32,7 @@ fn custom_value_type() {
// Expect the visit method to be called once with the custom type.
mock.expect_visit()
- .once()
+ .times(2)
.with(eq(OwnedStatic(MyValue)))
.return_const(VisitResult::Control(Flow::Done));
@@ -42,10 +41,16 @@ fn custom_value_type() {
let visitor: &mut dyn Value<OwnedStatic<MyValue>, Blocking> = &mut mock;
// Visit the value.
- let result = visitor.visit(OwnedStatic(MyValue)).into_innter();
+ let result = visitor.visit(OwnedStatic(MyValue)).into_inner();
// The mock returns that it is done.
assert_eq!(result, VisitResult::Control(Flow::Done));
+
+ let visitor: &mut (dyn AnyTrait + Send + Sync) = &mut mock;
+ assert_eq!(
+ visit_value::<_, Blocking>(DynVisitor(visitor), OwnedStatic(MyValue)).into_inner(),
+ VisitResult::Control(Flow::Done)
+ );
}
/// Tests that a value with a lifetime can be given to the value protocol.
@@ -67,7 +72,7 @@ fn borrowed_value() {
// Expect the visit method to be called once with the borrowed value.
mock.expect_visit()
- .once()
+ .times(2)
.withf(|BorrowedStatic(value)| *value == "test")
.return_const(VisitResult::Control(Flow::Done));
@@ -76,6 +81,12 @@ fn borrowed_value() {
// Visit the borrowed value.
visitor.visit(BorrowedStatic(value));
+
+ let visitor: &mut (dyn AnyTrait + Send + Sync) = &mut mock;
+ assert_eq!(
+ visit_value::<_, Blocking>(DynVisitor(visitor), BorrowedStatic(value)).into_inner(),
+ VisitResult::Control(Flow::Done)
+ );
}
// Make sure the compiler doesn't do anything funny with the lifetime.
@@ -161,19 +172,19 @@ fn all_visit_results() {
// Visit can return a done.
assert_eq!(
- visitor.visit(OwnedStatic(0)).into_innter(),
+ visitor.visit(OwnedStatic(0)).into_inner(),
VisitResult::Control(Flow::Done)
);
// Visit can return an error signal.
assert_eq!(
- visitor.visit(OwnedStatic(1)).into_innter(),
+ visitor.visit(OwnedStatic(1)).into_inner(),
VisitResult::Control(Flow::Err)
);
// Visit can return a continue.
assert_eq!(
- visitor.visit(OwnedStatic(2)).into_innter(),
+ visitor.visit(OwnedStatic(2)).into_inner(),
VisitResult::Control(Flow::Continue)
);
@@ -181,7 +192,7 @@ fn all_visit_results() {
// 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(),
+ visitor.visit(OwnedStatic(3)).into_inner(),
VisitResult::Skipped(OwnedStatic(3))
);
}
@@ -205,7 +216,7 @@ fn value_proto() {
#[test]
fn as_hint() {
{
- let mut mock = MockHintVisitor::<ValueProto<OwnedStatic<i32>, Blocking>, Blocking>::new();
+ let mut mock = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new();
mock.expect_known().once().return_const(
(|_, _hint| {
@@ -215,11 +226,11 @@ fn as_hint() {
}) as KnownFactory<ValueProto<OwnedStatic<i32>, Blocking>>,
);
- let walker: &mut dyn Hint<ValueProto<OwnedStatic<i32>, Blocking>, Blocking> = &mut mock;
+ let walker: &mut dyn Hint<ValueProto<OwnedStatic<i32>, Blocking>> = &mut mock;
// The value protocol has no hint data, and it has no known data.
assert_eq!(
- walker.known(&()).into_innter(),
+ walker.known(&()).into_inner(),
Ok(ValueKnown {
preview: Some(&OwnedStatic(42))
})
@@ -227,8 +238,7 @@ fn as_hint() {
}
{
- let mut mock =
- MockHintVisitor::<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking>::new();
+ let mut mock = MockHintWalker::<ValueProto<BorrowedStaticHrt<i32>, Blocking>>::new();
mock.expect_known().once().return_const(
(|_, _hint| {
@@ -238,12 +248,11 @@ fn as_hint() {
}) as KnownFactory<ValueProto<BorrowedStaticHrt<i32>, Blocking>>,
);
- let walker: &mut dyn Hint<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking> =
- &mut mock;
+ let walker: &mut dyn Hint<ValueProto<BorrowedStaticHrt<i32>, Blocking>> = &mut mock;
// The value protocol has no hint data, and it has no known data.
assert_eq!(
- walker.known(&()).into_innter(),
+ walker.known(&()).into_inner(),
Ok(ValueKnown {
preview: Some(&BorrowedStatic(&42))
})
@@ -251,20 +260,18 @@ fn as_hint() {
}
{
- let mut mock =
- MockHintVisitor::<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>, Blocking>::new();
+ let mut mock = MockHintWalker::<ValueProto<TempBorrowedMutStaticHrt<i32>, 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;
+ let walker: &mut dyn Hint<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>> = &mut mock;
// The value protocol has no hint data, and it has no known data.
assert_eq!(
- walker.known(&()).into_innter(),
+ walker.known(&()).into_inner(),
Ok(ValueKnown { preview: None })
);
}
diff --git a/tests/protocol_walker_hint.rs b/tests/protocol_walker_hint.rs
new file mode 100644
index 0000000..6f39590
--- /dev/null
+++ b/tests/protocol_walker_hint.rs
@@ -0,0 +1,313 @@
+use std::any::TypeId;
+
+use common::protocol::hint::MockHintWalker;
+use treaty::{
+ any::TypeNameId,
+ effect::{Blocking, Effect, Future, Spin},
+ hkt::higher_ranked_type,
+ protocol::{
+ walker::hint::{self, Hint, HintMeta, HintProto, Meta, MetaKnown}, DynVisitor
+ },
+ Flow,
+};
+
+use crate::common::{builder::MockBuilder, protocol::hint::KnownFactory};
+
+mod common;
+
+/// This tests for the hint protocol being able to give the known info and being able to hint.
+#[test]
+fn can_get_known_and_hint() {
+ // The protocol we will hint for.
+ struct MyProtocol;
+
+ // The known value for the protocol.
+ #[derive(Debug, PartialEq)]
+ struct Known(f32);
+
+ // Link the higher ranked type with the known type.
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for Known = Known;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known = Known;
+ }
+ }
+
+ #[derive(Debug, PartialEq)]
+ struct Hint(i32);
+
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for Hint = Hint;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint = Hint;
+ }
+ }
+
+ // Enroll the protocol in the hint system.
+ impl HintMeta for MyProtocol {
+ type Known = Known;
+ type Hint = Hint;
+ type Effect = Blocking;
+ }
+
+ let mut mock = MockHintWalker::<MyProtocol>::new();
+
+ mock.expect_known()
+ .once()
+ .return_const((|_, Hint(hint)| Ok(Known(*hint as f32))) as KnownFactory<MyProtocol>);
+
+ mock.expect_hint()
+ .once()
+ .withf(|_visitor, Hint(hint)| *hint == 123)
+ .return_const(Flow::Done);
+
+ // Get the mock as a hint protocol trait object.
+ let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock;
+
+ // We can call known to get what the walker knows about the protocol.
+ assert_eq!(walker.known(&Hint(42)).into_inner(), Ok(Known(42.0)));
+
+ {
+ // A hint needs the visitor for the walker to walk.
+ let mut mock = MockBuilder::<(), (), ()>::new();
+
+ // We can call hint to "commit" to the protocol and ask the walker to use it.
+ walker.hint(DynVisitor(&mut mock), Hint(123));
+ }
+}
+
+#[test]
+fn known_can_have_temp_mutable_borrow() {
+ struct MyProtocol;
+
+ struct KnownHrt;
+
+ #[derive(Debug, PartialEq)]
+ struct Known<'a>(&'a mut String);
+
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for KnownHrt = Known<'a>;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known<'a> = KnownHrt;
+ }
+ }
+
+ impl HintMeta for MyProtocol {
+ type Known = KnownHrt;
+ type Hint = ();
+ type Effect = Blocking;
+ }
+
+ struct Walker<'ctx>(&'ctx mut String);
+
+ impl<'ctx> Hint<'ctx, MyProtocol> for Walker<'ctx> {
+ fn hint<'a>(
+ &'a mut self,
+ _visitor: DynVisitor<'a, 'ctx>,
+ _hint: <MyProtocol as HintMeta>::Hint,
+ ) -> Future<'a, Flow, Blocking> {
+ unreachable!()
+ }
+
+ fn known<'a>(
+ &'a mut self,
+ (): &'a <MyProtocol as HintMeta>::Hint,
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, MyProtocol>, ()>, Blocking> {
+ self.0.push_str("test");
+
+ Blocking::<Spin>::ready(Ok(Known(self.0)))
+ }
+ }
+
+ let mut context = String::new();
+
+ {
+ let mut walker = Walker(&mut context);
+
+ // Get the mock as a hint protocol trait object.
+ let walker: &mut dyn Hint<MyProtocol> = &mut walker;
+
+ // We can call known to get what the walker knows about the protocol.
+ let mut x = String::from("test");
+ assert_eq!(walker.known(&()).into_inner(), Ok(Known(&mut x)));
+ }
+
+ drop(context);
+}
+
+#[test]
+fn known_can_have_context_borrow() {
+ struct MyProtocol;
+
+ struct KnownHrt;
+
+ #[derive(Debug, PartialEq)]
+ struct Known<'ctx>(&'ctx String);
+
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for KnownHrt = Known<'ctx>;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known<'ctx> = KnownHrt;
+ }
+ }
+
+ impl HintMeta for MyProtocol {
+ type Known = KnownHrt;
+ type Hint = ();
+ type Effect = Blocking;
+ }
+
+ struct Walker<'ctx>(&'ctx String);
+
+ impl<'ctx> Hint<'ctx, MyProtocol> for Walker<'ctx> {
+ fn hint<'a>(
+ &'a mut self,
+ _visitor: DynVisitor<'a, 'ctx>,
+ _hint: <MyProtocol as HintMeta>::Hint,
+ ) -> Future<'a, Flow, Blocking> {
+ unreachable!()
+ }
+
+ fn known<'a>(
+ &'a mut self,
+ (): &'a <MyProtocol as HintMeta>::Hint,
+ ) -> Future<'a, Result<MetaKnown<'a, 'ctx, MyProtocol>, ()>, Blocking> {
+ Blocking::<Spin>::ready(Ok(Known(self.0)))
+ }
+ }
+
+ let mut context = String::from("test");
+
+ let ctx = {
+ let mut walker = Walker(&mut context);
+
+ // Get the mock as a hint protocol trait object.
+ let walker: &mut dyn Hint<MyProtocol> = &mut walker;
+
+ // We can call known to get what the walker knows about the protocol.
+ let Ok(Known(y)) = walker.known(&()).into_inner() else {
+ unreachable!()
+ };
+ y
+ };
+
+ assert_eq!(ctx, "test");
+
+ drop(context);
+}
+
+#[test]
+fn hint_can_have_temp_mutable_borrow() {
+ struct MyProtocol;
+
+ struct HintHrt;
+
+ #[derive(Debug, PartialEq)]
+ struct Hint<'a>(&'a mut String);
+
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for HintHrt = Hint<'a>;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint<'a> = HintHrt;
+ }
+ }
+
+ impl HintMeta for MyProtocol {
+ type Known = ();
+ type Hint = HintHrt;
+ type Effect = Blocking;
+ }
+
+ let mut mock = MockHintWalker::new();
+
+ mock.expect_hint().once().returning(|_, hint: Hint| {
+ hint.0.push_str("test");
+
+ Flow::Done
+ });
+
+ {
+ // Get the mock as a hint protocol trait object.
+ let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock;
+
+ let mut visitor = MockBuilder::<(), (), ()>::new();
+
+ let mut temp = String::new();
+
+ // We can call known to get what the walker knows about the protocol.
+ assert_eq!(
+ walker.hint(DynVisitor(&mut visitor), Hint(&mut temp)).into_inner(),
+ Flow::Done
+ );
+
+ assert_eq!(temp, "test");
+ }
+}
+
+#[test]
+fn hint_can_have_context_borrow() {
+ struct MyProtocol;
+
+ struct HintHrt;
+
+ #[derive(Debug, PartialEq)]
+ struct Hint<'ctx>(&'ctx String);
+
+ higher_ranked_type! {
+ impl Meta {
+ impl['a, 'ctx] type T['a, 'ctx] for HintHrt = Hint<'ctx>;
+ impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint<'ctx> = HintHrt;
+ }
+ }
+
+ impl HintMeta for MyProtocol {
+ type Known = ();
+ type Hint = HintHrt;
+ type Effect = Blocking;
+ }
+
+ let mut mock = MockHintWalker::new();
+
+ mock.expect_hint().once().returning(|_, hint: Hint| {
+ assert_eq!(hint.0, "test");
+
+ Flow::Done
+ });
+
+ let context = String::from("test");
+
+ {
+ // Get the mock as a hint protocol trait object.
+ let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock;
+
+ let mut visitor = MockBuilder::<(), (), ()>::new();
+
+ // We can call known to get what the walker knows about the protocol.
+ assert_eq!(
+ walker.hint(DynVisitor(&mut visitor), Hint(&context)).into_inner(),
+ Flow::Done
+ );
+ }
+
+ drop(context);
+}
+
+#[test]
+fn hint_proto() {
+ struct MyProtocol;
+
+ impl HintMeta for MyProtocol {
+ type Known = ();
+ type Hint = ();
+ type Effect = Blocking;
+ }
+
+ // The type id of the higher ranked type.
+ let id = TypeId::of::<HintProto<MyProtocol>>();
+
+ // The type id for the lifetime containing value protocol trait object.
+ let name_id = TypeNameId::of_lower::<dyn hint::Hint<MyProtocol> + Send + Sync>();
+
+ // They should be the same.
+ assert_eq!(id, name_id.into_type_id());
+}
diff --git a/tests/walk.rs b/tests/walk.rs
deleted file mode 100644
index f83ef24..0000000
--- a/tests/walk.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-mod common;
-
-mod walkers;
diff --git a/tests/walkers/core.rs b/tests/walkers/core.rs
deleted file mode 100644
index c10aef3..0000000
--- a/tests/walkers/core.rs
+++ /dev/null
@@ -1 +0,0 @@
-mod r#struct;
diff --git a/tests/walkers/core/struct.rs b/tests/walkers/core/struct.rs
deleted file mode 100644
index 9ac2d59..0000000
--- a/tests/walkers/core/struct.rs
+++ /dev/null
@@ -1,146 +0,0 @@
-use mockall::{predicate::eq, Sequence};
-use treaty::{
- any::{OwnedStatic, TypeNameId},
- effect::{BlockOn, Blocking, Effect, Future, Spin},
- protocol::{
- visitor::{TagConst, TagProto, ValueProto},
- Visitor,
- },
- walkers::core::{
- r#struct::{StructTypeInfo, StructWalker},
- value::ValueWalker,
- },
- Builder, DefaultMode, Flow, Walker, TAG_STRUCT, TAG_TYPE_NAME,
-};
-
-use crate::common::{
- builder::MockBuilder,
- protocol::{tag::MockTagVisitor, visitor::MockValueVisitor},
-};
-
-struct Demo {
- a: bool,
- b: bool,
-}
-
-impl<'ctx, M> StructTypeInfo<'ctx, M> for Demo {
- const NAME: &'static str = "Demo";
-
- const FIELDS: &'static [&'static str] = &["a", "b"];
-
- type FieldError = ();
-
- type T = Demo;
-
- fn walk_field<'a, E: Effect>(
- index: usize,
- value: &'ctx Self::T,
- visitor: Visitor<'a, 'ctx>,
- ) -> Future<'a, Result<Flow, Self::FieldError>, E> {
- E::wrap(async move {
- match index {
- 0 => {
- let walker = ValueWalker::<bool>::new(value.a);
- Walker::<E>::walk(walker, visitor).await.unwrap();
- Ok(Flow::Continue)
- }
- 1 => {
- let walker = ValueWalker::<bool>::new(value.b);
- Walker::<E>::walk(walker, visitor).await.unwrap();
- Ok(Flow::Continue)
- }
- _ => Ok(Flow::Done),
- }
- })
- }
-}
-
-#[test]
-fn demo2() {
- let mut builder = MockBuilder::<(), (), ()>::new();
-
- let mut seq = Sequence::new();
-
- builder
- .expect_traits_mut()
- .times(4)
- .in_sequence(&mut seq)
- .return_var(None);
-
- builder
- .expect_traits_mut()
- .once()
- .with(eq(TypeNameId::of::<
- TagProto<TagConst<{ TAG_STRUCT.to_int() }>, Blocking>,
- >()))
- .in_sequence(&mut seq)
- .return_var(Some(Box::new({
- let mut mock = MockTagVisitor::<TagConst<{ TAG_STRUCT.to_int() }>, Blocking>::new();
-
- mock.expect_visit().once().returning(|_, walker| {
- let mut builder = MockBuilder::<(), (), ()>::new();
- assert_eq!(
- Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))),
- Flow::Done
- );
-
- Flow::Continue.into()
- });
-
- mock
- })));
-
- builder
- .expect_traits_mut()
- .once()
- .with(eq(TypeNameId::of::<
- TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, Blocking>,
- >()))
- .in_sequence(&mut seq)
- .return_var(Some(Box::new({
- let mut mock = MockTagVisitor::<TagConst<{ TAG_TYPE_NAME.to_int() }>, Blocking>::new();
-
- mock.expect_visit().return_once(|_, walker| {
- let mut builder = MockBuilder::<(), (), ()>::new();
-
- builder
- .expect_traits_mut()
- .once()
- .with(eq(TypeNameId::of::<
- ValueProto<OwnedStatic<&'static str>, Blocking>,
- >()))
- .return_var(Some(Box::new({
- let mut mock =
- MockValueVisitor::<OwnedStatic<&'static str>, Blocking>::new();
-
- mock.expect_visit()
- .once()
- .with(eq(OwnedStatic("Demo")))
- .return_const(Flow::Done);
-
- mock
- })));
-
- assert_eq!(
- Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))),
- Flow::Done
- );
-
- Flow::Continue.into()
- });
-
- mock
- })));
-
- builder
- .expect_traits_mut()
- .times(3)
- .in_sequence(&mut seq)
- .return_var(None);
-
- let value = Demo { a: true, b: false };
-
- let walker = StructWalker::<Demo, Demo, DefaultMode, Blocking>::new(&value);
-
- Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))).unwrap();
-}
diff --git a/tests/walkers/mod.rs b/tests/walkers/mod.rs
deleted file mode 100644
index 9816037..0000000
--- a/tests/walkers/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-mod core;