-rw-r--r--Cargo.toml2
-rw-r--r--src/build/builders/core.rs2
-rw-r--r--src/build/builders/core/enum.rs4
-rw-r--r--src/build/builders/core/struct.rs32
-rw-r--r--src/build/builders/core/value.rs39
-rw-r--r--src/effect.rs9
-rw-r--r--src/effect/async.rs35
-rw-r--r--src/effect/blocking.rs9
-rw-r--r--src/lib.rs2
-rw-r--r--src/protocol/visitor.rs2
-rw-r--r--src/protocol/visitor/recoverable.rs10
-rw-r--r--src/protocol/visitor/request_hint.rs42
-rw-r--r--src/protocol/visitor/sequence.rs10
-rw-r--r--src/protocol/visitor/tag.rs6
-rw-r--r--src/protocol/visitor/value.rs7
-rw-r--r--src/protocol/walker/hint.rs65
-rw-r--r--src/transform.rs17
-rw-r--r--src/walk/walkers/core.rs1
-rw-r--r--src/walk/walkers/core/int.rs281
-rw-r--r--src/walk/walkers/core/struct.rs55
-rw-r--r--src/walk/walkers/serde/deserializer.rs345
-rw-r--r--tests/builder_value.rs9
-rw-r--r--tests/common/mod.rs2
-rw-r--r--tests/common/protocol/hint.rs9
-rw-r--r--tests/common/protocol/recoverable.rs12
-rw-r--r--tests/common/protocol/request_hint.rs18
-rw-r--r--tests/common/protocol/sequence.rs11
-rw-r--r--tests/common/protocol/tag.rs9
-rw-r--r--tests/protocol_visitor_recoverable.rs29
-rw-r--r--tests/protocol_visitor_request_hint.rs41
-rw-r--r--tests/protocol_visitor_sequence.rs26
-rw-r--r--tests/serde_deserializer.rs23
-rw-r--r--tests/walker_struct.rs153
33 files changed, 1013 insertions, 304 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1608b1c..1d27426 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
macro_rules_attribute = "0.2.0"
futures = "0.3.30"
pin-project = "1.1.5"
-serde = { version = "1.0", default-features = false, optional = true }
+serde = { version = "1.0", optional = true }
[features]
default = ["std", "serde"]
diff --git a/src/build/builders/core.rs b/src/build/builders/core.rs
index 4a7182d..55c7bfb 100644
--- a/src/build/builders/core.rs
+++ b/src/build/builders/core.rs
@@ -32,7 +32,7 @@ any_trait! {
impl NoopVisitor {
pub fn walk_dyn<'ctx: 'e, 'walker: 'e, 'e, E: Effect>(
walker: DynWalkerObjSafe<'walker, 'ctx, E>,
- ) -> ErasedEffective<'e, VisitResult<DynWalkerObjSafe<'walker, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'e, VisitResult, E> {
E::ready(NoopVisitor::new()).as_ctx_map(|noop| {
walker
.walk(DynVisitor(noop))
diff --git a/src/build/builders/core/enum.rs b/src/build/builders/core/enum.rs
index 92e3149..4e29bc4 100644
--- a/src/build/builders/core/enum.rs
+++ b/src/build/builders/core/enum.rs
@@ -147,7 +147,7 @@ where
fn visit<'a>(
&'a mut self,
scope: DynRecoverableScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'a, VisitResult, E> {
match core::mem::replace(&mut self.inner, Inner::Temp) {
Inner::Seed(seed) => Info::guess_variant(seed, scope).map(|result| {
self.inner = Inner::Value(result);
@@ -186,7 +186,7 @@ where
&'a mut self,
_kind: tags::Variant,
walker: DynWalkerObjSafe<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynWalkerObjSafe<'b, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'c, VisitResult, E> {
let visitor = VariantVisitor::<Info, Mode, E> { marker: None };
E::as_ctx((visitor, walker), |(visitor, walker)| {
diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs
index 890ffda..6bc1ef1 100644
--- a/src/build/builders/core/struct.rs
+++ b/src/build/builders/core/struct.rs
@@ -243,19 +243,22 @@ where
E: Effect,
{
#[inline(always)]
- fn request_hint<'a>(
- &'a mut self,
- walker: DynWalker<'a, 'ctx>,
- ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ fn request_hint<'this: 'e, 'walker: 'e, 'e>(
+ &'this mut self,
+ walker: DynWalker<'walker, 'ctx>,
+ ) -> ErasedEffective<'e, VisitResult, E>
+ where
+ 'ctx: 'this + 'walker,
+ {
E::as_ctx((self, walker), |(this, walker)| {
// Start with a hint to use the value protocol to directly transfer the
// struct value.
- hint_protocol::<ValueProto<Info::ValueT, E>>(walker.cast(), *this, ()).cast()
+ hint_protocol::<ValueProto<Info::ValueT, E>, _>(walker.cast(), *this, ()).cast()
})
.if_not_finished(|(this, walker)| {
// Next hint that the struct protocol should be used to switch into
// map-like if the walker supports it.
- hint_protocol::<TagProto<tags::Struct, E>>(
+ hint_protocol::<TagProto<tags::Struct, E>, _>(
walker.cast(),
*this,
TagHint { kind: TagConst },
@@ -266,7 +269,7 @@ where
// If the struct hint didn't work,
// then hint that the map protocol should be used to switch into
// map-like if the walker supports it.
- hint_protocol::<TagProto<tags::Map, E>>(
+ hint_protocol::<TagProto<tags::Map, E>, _>(
walker.cast(),
*this,
TagHint { kind: TagConst },
@@ -276,7 +279,7 @@ where
.if_not_finished(|(this, walker)| {
// Lastly hint to use a sequence to get the field values.
// We hint with the exact number of fields we are expecting.
- hint_protocol::<SequenceProto<E>>(
+ hint_protocol::<SequenceProto<E>, _>(
walker.cast(),
*this,
SequenceHint {
@@ -285,10 +288,7 @@ where
)
.cast()
})
- .map(|((_, walker), result)| match result {
- VisitResult::Skipped(()) => VisitResult::Skipped(walker),
- VisitResult::Control(flow) => VisitResult::Control(flow),
- })
+ .remove_ctx()
}
}
@@ -328,7 +328,7 @@ where
&'this mut self,
_kind: tags::Struct,
walker: DynWalkerObjSafe<'walker, 'ctx, E>,
- ) -> ErasedEffective<'e, VisitResult<DynWalkerObjSafe<'walker, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'e, VisitResult, E> {
// If this protocol is used then we need to create the builders.
E::as_ctx(self, |this| this.make_builders().cast()).then(|(this, _)| {
if let Inner::Builders { kind, .. } = &mut this.inner {
@@ -354,7 +354,7 @@ where
&'this mut self,
_kind: tags::Map,
walker: DynWalkerObjSafe<'walker, 'ctx, E>,
- ) -> ErasedEffective<'e, VisitResult<DynWalkerObjSafe<'walker, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'e, VisitResult, E> {
// If this protocol is used then we need to create the builders.
E::as_ctx(self, |this| this.make_builders().cast()).then(|(this, _)| {
if let Inner::Builders { kind, .. } = &mut this.inner {
@@ -382,7 +382,7 @@ where
fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
scope: DynSequenceScope<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E>
+ ) -> ErasedEffective<'c, VisitResult, E>
where
'ctx: 'a + 'b + 'c,
{
@@ -481,7 +481,7 @@ where
&'a mut self,
_key: tags::Key,
walker: DynWalkerObjSafe<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynWalkerObjSafe<'b, 'ctx, E>>, E> {
+ ) -> ErasedEffective<'c, VisitResult, E> {
let visitor = NameVisitor::<I, M, E> {
field_marker: None,
_marker: Default::default(),
diff --git a/src/build/builders/core/value.rs b/src/build/builders/core/value.rs
index b969ac2..22fe995 100644
--- a/src/build/builders/core/value.rs
+++ b/src/build/builders/core/value.rs
@@ -106,14 +106,17 @@ any_trait! {
}
impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T, NotCloneable, E> {
- fn request_hint<'a>(
- &'a mut self,
- walker: DynWalker<'a, 'ctx>,
- ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ fn request_hint<'this: 'e, 'walker: 'e, 'e>(
+ &'this mut self,
+ walker: DynWalker<'walker, 'ctx>,
+ ) -> ErasedEffective<'e, VisitResult, E>
+ where
+ 'ctx: 'this + 'walker,
+ {
E::as_ctx((self, walker), |(this, walker)| {
- hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast()
+ hint_protocol::<ValueProto<OwnedStatic<T>, E>, _>(walker.cast(), *this, ()).cast()
})
- .map(|((_, walker), result)| result.map_skipped(|_| walker))
+ .remove_ctx()
}
}
@@ -121,28 +124,32 @@ impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T,
where
T: Clone,
{
- fn request_hint<'a>(
- &'a mut self,
- walker: DynWalker<'a, 'ctx>,
- ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ fn request_hint<'this: 'e, 'walker: 'e, 'e>(
+ &'this mut self,
+ walker: DynWalker<'walker, 'ctx>,
+ ) -> ErasedEffective<'e, VisitResult, E>
+ where
+ 'ctx: 'this + 'walker,
+ {
E::as_ctx((self, walker), |(this, walker)| {
- hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast()
+ hint_protocol::<ValueProto<OwnedStatic<T>, E>, _>(walker.cast(), *this, ()).cast()
})
.if_not_finished(|(this, walker)| {
- hint_protocol::<ValueProto<BorrowedStaticHrt<T>, E>>(walker.cast(), *this, ()).cast()
+ hint_protocol::<ValueProto<BorrowedStaticHrt<T>, E>, _>(walker.cast(), *this, ()).cast()
})
.if_not_finished(|(this, walker)| {
- hint_protocol::<ValueProto<TempBorrowedStaticHrt<T>, E>>(walker.cast(), *this, ())
+ hint_protocol::<ValueProto<TempBorrowedStaticHrt<T>, E>, _>(walker.cast(), *this, ())
.cast()
})
.if_not_finished(|(this, walker)| {
- hint_protocol::<ValueProto<BorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ()).cast()
+ hint_protocol::<ValueProto<BorrowedMutStaticHrt<T>, E>, _>(walker.cast(), *this, ())
+ .cast()
})
.if_not_finished(|(this, walker)| {
- hint_protocol::<ValueProto<TempBorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ())
+ hint_protocol::<ValueProto<TempBorrowedMutStaticHrt<T>, E>, _>(walker.cast(), *this, ())
.cast()
})
- .map(|((_, walker), result)| result.map_skipped(|_| walker))
+ .remove_ctx()
}
}
diff --git a/src/effect.rs b/src/effect.rs
index 092705e..0b1a76b 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -95,7 +95,16 @@ pub type ErasedEffective<'lt, Output, E, Bound = ()> = <
Erased::ForLt<'lt, Output, E, &'lt (Output, Bound)>
>::Effective;
+pub trait BlockOn: Ss + Sized + 'static {
+ fn block_on<F>(future: F) -> F::Output
+ where
+ F: core::future::Future + Ss,
+ <F as core::future::Future>::Output: Ss;
+}
+
pub trait Effect: Join<Effect = Self> + TryJoin<Effect = Self> + Ss + Sized + 'static {
+ type BlockOn: BlockOn;
+
type Erased<T: Ss>: Erased::Hkt<T, Self>;
fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self>;
diff --git a/src/effect/async.rs b/src/effect/async.rs
index 1a910d4..c1a6f06 100644
--- a/src/effect/async.rs
+++ b/src/effect/async.rs
@@ -5,11 +5,13 @@ use pin_project::pin_project;
use crate::hkt::Marker;
+use self::blocking::Spin;
+
use super::*;
-pub enum Async {}
+pub struct Async<B = Spin>(Marker<B>);
-pub struct ErasedFutureHrt<T>(Marker<T>);
+pub struct ErasedFutureHrt<T, B>(Marker<(T, B)>);
enum ErasedFutureKind<'lt, T> {
Boxed(Pin<Box<dyn Future<Output = T> + Send + Sync + 'lt>>),
@@ -17,8 +19,9 @@ enum ErasedFutureKind<'lt, T> {
}
#[must_use]
-pub struct ErasedFuture<'lt, T> {
+pub struct ErasedFuture<'lt, T, B> {
kind: ErasedFutureKind<'lt, T>,
+ _marker: Marker<B>,
}
#[pin_project(project = EffectFutureKindProj)]
@@ -49,20 +52,25 @@ impl<'lt, T> Future for EffectFuture<'lt, T> {
}
}
-impl<'lt, T: Ss, O> Erased::ForLt<'lt, T, Async, &'lt (T, O)> for ErasedFutureHrt<T> {
- type Effective = ErasedFuture<'lt, T>;
+impl<'lt, T: Ss, B: BlockOn, O> Erased::ForLt<'lt, T, Async<B>, &'lt (T, O)>
+ for ErasedFutureHrt<T, B>
+{
+ type Effective = ErasedFuture<'lt, T, B>;
}
-impl<T: Ss> Erased::Hkt<T, Async> for ErasedFutureHrt<T> {
+impl<T: Ss, B: BlockOn> Erased::Hkt<T, Async<B>> for ErasedFutureHrt<T, B> {
type Hrt<O> = Self;
}
-impl Effect for Async {
- type Erased<T: Ss> = ErasedFutureHrt<T>;
+impl<B: BlockOn> Effect for Async<B> {
+ type BlockOn = B;
+
+ type Erased<T: Ss> = ErasedFutureHrt<T, B>;
fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self> {
ErasedFuture {
kind: ErasedFutureKind::Ready(value),
+ _marker: Default::default(),
}
}
@@ -73,11 +81,12 @@ impl Effect for Async {
{
ErasedFuture {
kind: ErasedFutureKind::Boxed(Box::pin(future)),
+ _marker: Default::default(),
}
}
}
-impl<'lt, U: Ss + 'lt> Effective<'lt> for ErasedFuture<'lt, U> {
+impl<'lt, U: Ss + 'lt, B: BlockOn> Effective<'lt> for ErasedFuture<'lt, U, B> {
fn cast<'wrap, X>(self) -> ErasedEffective<'wrap, Self::Output, Self::Effect, X>
where
'lt: 'wrap,
@@ -85,7 +94,7 @@ impl<'lt, U: Ss + 'lt> Effective<'lt> for ErasedFuture<'lt, U> {
self
}
- type Effect = Async;
+ type Effect = Async<B>;
type Output = U;
@@ -183,17 +192,19 @@ impl<'lt, U: Ss + 'lt> Effective<'lt> for ErasedFuture<'lt, U> {
ErasedFuture {
kind: ErasedFutureKind::Boxed(Box::pin(fut)),
+ _marker: Default::default(),
}
}
fn ready(value: Self::Output) -> Self {
ErasedFuture {
kind: ErasedFutureKind::Ready(value),
+ _marker: Default::default(),
}
}
}
-impl Join for Async {
+impl<B: BlockOn> Join for Async<B> {
type Effect = Self;
fn two<'a, T0, T1>(
@@ -229,7 +240,7 @@ impl Join for Async {
}
}
-impl TryJoin for Async {
+impl<B: BlockOn> TryJoin for Async<B> {
type Effect = Self;
fn two<'a, T0, T1, F0, F1>(
diff --git a/src/effect/blocking.rs b/src/effect/blocking.rs
index 39ea3ac..75d6063 100644
--- a/src/effect/blocking.rs
+++ b/src/effect/blocking.rs
@@ -6,13 +6,6 @@ use crate::hkt::Marker;
use super::*;
-pub trait BlockOn: 'static {
- fn block_on<F>(future: F) -> F::Output
- where
- F: core::future::Future + Send,
- <F as core::future::Future>::Output: Send;
-}
-
pub struct Blocking<B = Spin>(Marker<B>);
#[must_use]
@@ -34,6 +27,8 @@ impl<T: Ss, B: BlockOn> Erased::Hkt<T, Blocking<B>> for Value<T, B> {
}
impl<B: BlockOn> Effect for Blocking<B> {
+ type BlockOn = B;
+
type Erased<T: Ss> = Value<T, B>;
fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self> {
diff --git a/src/lib.rs b/src/lib.rs
index fd75d72..361f9f8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -275,7 +275,7 @@ pub mod demo {
#[test]
fn demo() {
- use crate::effect::blocking::BlockOn as _;
+ use crate::effect::BlockOn as _;
assert_eq!(ident(X { a: true, b: false }), Y { a: true, b: false });
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs
index bf2b8d2..e414b4c 100644
--- a/src/protocol/visitor.rs
+++ b/src/protocol/visitor.rs
@@ -20,7 +20,7 @@ pub use value::*;
#[derive(Copy, Clone)]
#[must_use]
-pub enum VisitResult<S> {
+pub enum VisitResult<S = ()> {
/// The protocol was not used.
///
/// This either means the visitor doesn't support the protocol at all, or
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs
index ce7a181..b43344f 100644
--- a/src/protocol/visitor/recoverable.rs
+++ b/src/protocol/visitor/recoverable.rs
@@ -3,7 +3,7 @@ use crate::{
effect::{Effect, ErasedEffective, ReadyExt as _},
hkt::Marker,
protocol::{
- walker::hint::{HintMeta, Meta},
+ walker::hint::{HasProtocol, HintMeta, Meta},
DynVisitor,
},
Status,
@@ -15,7 +15,7 @@ pub trait Recoverable<'ctx, E: Effect> {
fn visit<'a>(
&'a mut self,
scope: DynRecoverableScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E>;
+ ) -> ErasedEffective<'a, VisitResult, E>;
}
pub struct RecoverableProto<E: Effect>(Marker<E>);
@@ -66,12 +66,14 @@ impl<E: Effect> HintMeta for RecoverableProto<E> {
pub fn visit_recoverable<'a, 'ctx, E: Effect>(
visitor: DynVisitor<'a, 'ctx>,
scope: DynRecoverableScope<'a, 'ctx, E>,
-) -> ErasedEffective<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> {
+) -> ErasedEffective<'a, VisitResult, 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 {
// If the visitor doesn't support request hint then we continue.
- VisitResult::Skipped(scope).ready()
+ VisitResult::Skipped(()).ready()
}
}
+
+impl<'ctx, T, E: Effect> HasProtocol<RecoverableProto<E>> for T where T: Recoverable<'ctx, E> {}
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index 0c11fcd..a110adb 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,6 +1,8 @@
use crate::{
any::TypeName,
- effect::{Effect, ErasedEffective, ReadyExt as _},
+ effect::{
+ Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, ReadyExt as _,
+ },
hkt::Marker,
protocol::{DynVisitor, DynWalker},
};
@@ -13,10 +15,12 @@ pub trait RequestHint<'ctx, E: Effect> {
///
/// `walker` is what the visitor (`self`) will call to give a hint using the
/// [`Hint`][crate::builtins::walker::Hint] protocol.
- fn request_hint<'a>(
- &'a mut self,
- walker: DynWalker<'a, 'ctx>,
- ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E>;
+ fn request_hint<'this: 'e, 'walker: 'e, 'e>(
+ &'this mut self,
+ walker: DynWalker<'walker, 'ctx>,
+ ) -> ErasedEffective<'e, VisitResult, E>
+ where
+ 'ctx: 'this + 'walker;
}
pub struct RequestHintProto<E: Effect>(Marker<E>);
@@ -43,15 +47,21 @@ where
/// If [`Flow::Done`] is returned then the visitor doesn't need any more information and the walker
/// should stop walking.
/// If [`Flow::Break`] is returned then there was an error and the walker should stop walking.
-pub fn request_hint<'a, 'ctx, E: Effect>(
- visitor: DynVisitor<'a, 'ctx>,
- walker: DynWalker<'a, 'ctx>,
-) -> ErasedEffective<'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 {
- // If the visitor doesn't support request hint then we continue.
- VisitResult::Skipped(walker).ready()
- }
+pub fn request_hint<'ctx: 'visitor + 'walker, 'visitor: 'e, 'walker: 'e, 'e, E: Effect>(
+ visitor: DynVisitor<'visitor, 'ctx>,
+ walker: DynWalker<'walker, 'ctx>,
+) -> ErasedEffective<'e, VisitResult<DynWalker<'walker, 'ctx>>, E> {
+ E::as_ctx((visitor, walker), |(visitor, walker)| {
+ if let Some(object) = visitor.0.upcast_mut::<RequestHintProto<E>>() {
+ // Allow the visitor to give a hint if it wants.
+ object
+ .request_hint(walker.cast())
+ .map(|x| x.unit_skipped())
+ .cast()
+ } else {
+ // If the visitor doesn't support request hint then we continue.
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .map(|((_, walker), result)| result.map_skipped(|_| walker))
}
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index 4138be1..f261eca 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -3,7 +3,7 @@ use crate::{
effect::{Effect, ErasedEffective, ReadyExt as _},
hkt::Marker,
protocol::{
- walker::hint::{HintMeta, Meta},
+ walker::hint::{HasProtocol, HintMeta, Meta},
DynVisitor,
},
Flow,
@@ -19,7 +19,7 @@ pub trait Sequence<'ctx, E: Effect> {
fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
scope: DynSequenceScope<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E>
+ ) -> ErasedEffective<'c, VisitResult, E>
where
'ctx: 'a;
}
@@ -91,12 +91,14 @@ impl<E: Effect> HintMeta for SequenceProto<E> {
pub fn visit_sequence<'a, 'ctx, E: Effect>(
visitor: DynVisitor<'a, 'ctx>,
scope: DynSequenceScope<'a, 'ctx, E>,
-) -> ErasedEffective<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
+) -> ErasedEffective<'a, VisitResult, E> {
if let Some(object) = visitor.0.upcast_mut::<SequenceProto<E>>() {
// Allow the visitor to walk the sequence scope.
object.visit(scope)
} else {
// If the visitor doesn't support sequence then we continue.
- VisitResult::Skipped(scope).ready()
+ VisitResult::Skipped(()).ready()
}
}
+
+impl<'ctx, T, E: Effect> HasProtocol<SequenceProto<E>> for T where T: Sequence<'ctx, E> {}
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index a1f189b..ffc692a 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -5,7 +5,7 @@ use crate::{
effect::{Effect, Effective, EffectiveExt, ErasedEffective, ReadyExt},
hkt::Marker,
protocol::{
- walker::hint::{HintMeta, Meta},
+ walker::hint::{HasProtocol, HintMeta, Meta},
DynVisitor,
},
symbol::Symbol,
@@ -54,7 +54,7 @@ pub trait Tag<'ctx, K: TagKind, E: Effect> {
&'a mut self,
kind: K,
walker: DynWalkerObjSafe<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynWalkerObjSafe<'b, 'ctx, E>>, E>;
+ ) -> ErasedEffective<'c, VisitResult, E>;
}
pub struct TagProto<K: TagKind, E: Effect>(Marker<(K, E)>);
@@ -221,3 +221,5 @@ fn map_walker_err<'ctx, K: TagKind, W: Walker<'ctx, E>, E: Effect>(
DynWalkerError::WasWalked(_) => TagError::was_walked(kind),
}
}
+
+impl<'ctx, T, K: TagKind, E: Effect> HasProtocol<TagProto<K, E>> for T where T: Tag<'ctx, K, E> {}
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index 82c7141..8a42627 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -7,7 +7,7 @@ use crate::{
effect::{Effect, ErasedEffective, ReadyExt as _},
hkt::Marker,
protocol::{
- walker::hint::{HintMeta, Meta},
+ walker::hint::{HasProtocol, HintMeta, Meta},
DynVisitor,
},
};
@@ -111,3 +111,8 @@ pub fn visit_value<
VisitResult::Skipped(value).ready()
}
}
+
+impl<'ctx, T, U: TypeName::MemberType, E: Effect> HasProtocol<ValueProto<U, E>> for T where
+ T: Value<'ctx, U, E>
+{
+}
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 683436a..049d881 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -4,11 +4,13 @@
//! this module gives a protocol by which a visitor can give a hint
//! to the walker about what it is expecting.
+use core::ops::{Deref, DerefMut};
+
use crate::{
- any::TypeName,
- effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _},
+ any::{AnyTrait, TypeName},
+ effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _, Ss},
hkt::Marker,
- protocol::{visitor::VisitResult, DynWalker},
+ protocol::{visitor::VisitResult, DynVisitor, DynWalker},
Flow,
};
@@ -72,9 +74,9 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
/// This should only be called once per [`RequestHint`].
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
- visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>,
+ visitor: DynVisitorWith<'visitor, 'ctx, Protocol>,
hint: MetaHint<'hint, 'ctx, Protocol>,
- ) -> ErasedEffective<'e, Flow, Protocol::Effect>
+ ) -> ErasedEffective<'e, VisitResult, Protocol::Effect>
where
'ctx: 'this + 'visitor + 'hint + 'e;
@@ -85,6 +87,47 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, Protocol>, ()>, Protocol::Effect>;
}
+pub struct DynVisitorWith<'temp, 'ctx, Protocol: ?Sized> {
+ visitor: DynVisitor<'temp, 'ctx>,
+ _marker: Marker<Protocol>,
+}
+
+pub trait HasProtocol<Protocol: ?Sized> {}
+
+impl<'temp, 'ctx: 'temp, Protocol: ?Sized + HintMeta> DynVisitorWith<'temp, 'ctx, Protocol> {
+ pub fn new<T>(visitor: &'temp mut T) -> Self
+ where
+ T: AnyTrait<'ctx> + HasProtocol<Protocol> + Ss,
+ {
+ Self {
+ visitor: DynVisitor(visitor),
+ _marker: Default::default(),
+ }
+ }
+
+ pub fn as_known(&mut self) -> &mut TypeName::T<'_, 'ctx, Protocol> {
+ self.visitor.upcast_mut::<Protocol>().unwrap()
+ }
+
+ pub fn into_inner(self) -> DynVisitor<'temp, 'ctx> {
+ self.visitor
+ }
+}
+
+impl<'temp, 'ctx, Protocol: ?Sized> Deref for DynVisitorWith<'temp, 'ctx, Protocol> {
+ type Target = DynVisitor<'temp, 'ctx>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.visitor
+ }
+}
+
+impl<'temp, 'ctx, Protocol: ?Sized> DerefMut for DynVisitorWith<'temp, 'ctx, Protocol> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.visitor
+ }
+}
+
pub struct HintProto<Protocol: ?Sized>(Marker<Protocol>);
impl<'a, 'ctx, Protocol: ?Sized> TypeName::MemberTypeForLt<'a, 'ctx, &'a &'ctx ()>
@@ -110,13 +153,19 @@ pub fn hint_protocol<
'hint: 'e,
'e,
Protocol: ?Sized + HintMeta,
+ T,
>(
walker: DynWalker<'walker, 'ctx>,
- visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>,
+ visitor: &'visitor mut T,
hint: MetaHint<'hint, 'ctx, Protocol>,
-) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect> {
+) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect>
+where
+ T: AnyTrait<'ctx> + HasProtocol<Protocol> + Ss,
+{
if let Some(object) = walker.0.upcast_mut::<HintProto<Protocol>>() {
- object.hint(visitor, hint).map(Into::into)
+ object
+ .hint(DynVisitorWith::new(visitor), hint)
+ .map(Into::into)
} else {
VisitResult::Skipped(()).ready()
}
diff --git a/src/transform.rs b/src/transform.rs
index b9cc346..fc37e01 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -42,7 +42,7 @@ pub enum BuildError<B, W> {
Both(B, W),
}
-impl<B, W> core::fmt::Debug for BuildError<B, W>
+impl<B, W> core::fmt::Debug for BuildError<B, W>
where
B: core::fmt::Debug,
W: core::fmt::Debug,
@@ -57,7 +57,12 @@ where
pub trait BuildExt {
/// Build a value of this type using the default builder.
- fn build<'ctx, W>(walker: W) -> Result<Self, BuildError<<Self::Builder as BuilderTypes>::Error, <W as Walker<'ctx, Blocking>>::Error>>
+ fn build<'ctx, W>(
+ walker: W,
+ ) -> Result<
+ Self,
+ BuildError<<Self::Builder as BuilderTypes>::Error, <W as Walker<'ctx, Blocking>>::Error>,
+ >
where
Self: Build<'ctx, DefaultMode, Blocking>,
<Self::Builder as BuilderTypes>::Seed: Default,
@@ -72,7 +77,13 @@ pub trait BuildExt {
fn build_async<'ctx, W>(
walker: W,
- ) -> impl Future<Output = Result<Self, BuildError<<Self::Builder as BuilderTypes>::Error, <W as Walker<'ctx, Async>>::Error>>> + Send + Sync
+ ) -> impl Future<
+ Output = Result<
+ Self,
+ BuildError<<Self::Builder as BuilderTypes>::Error, <W as Walker<'ctx, Async>>::Error>,
+ >,
+ > + Send
+ + Sync
where
Self: Build<'ctx, DefaultMode, Async>,
<Self::Builder as BuilderTypes>::Seed: Default,
diff --git a/src/walk/walkers/core.rs b/src/walk/walkers/core.rs
index 6b6b128..bc1fbd6 100644
--- a/src/walk/walkers/core.rs
+++ b/src/walk/walkers/core.rs
@@ -1,6 +1,7 @@
// pub mod array;
pub mod bool;
+pub mod int;
pub mod key_value;
pub mod noop;
pub mod r#struct;
diff --git a/src/walk/walkers/core/int.rs b/src/walk/walkers/core/int.rs
new file mode 100644
index 0000000..97dc54d
--- /dev/null
+++ b/src/walk/walkers/core/int.rs
@@ -0,0 +1,281 @@
+use crate::{
+ any::OwnedStatic,
+ any_trait,
+ effect::{Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss},
+ hkt::Marker,
+ never::Never,
+ protocol::{
+ visitor::{
+ request_hint, visit_value, EffectiveVisitExt as _, ValueKnown, ValueProto, VisitResult,
+ },
+ walker::hint::{DynVisitorWith, Hint, HintProto, MetaHint, MetaKnown},
+ DynVisitor, DynWalker,
+ },
+ Flow, Walker,
+};
+
+pub struct IntegerWalker<T, E> {
+ value: T,
+ _marker: Marker<E>,
+}
+
+pub trait Integer:
+ 'static
+ + Copy
+ + core::fmt::Debug
+ + core::fmt::Display
+ + Ss
+ + TryInto<u8>
+ + TryInto<u16>
+ + TryInto<u32>
+ + TryInto<u64>
+ + TryInto<u128>
+ + TryInto<usize>
+ + TryInto<i8>
+ + TryInto<i16>
+ + TryInto<i32>
+ + TryInto<i64>
+ + TryInto<i128>
+ + TryInto<isize>
+{
+}
+
+fn try_into<T: TryInto<U>, U>(value: T) -> Option<U> {
+ value.try_into().ok()
+}
+
+impl<'ctx, T, E> IntegerWalker<T, E> {
+ pub fn new(value: T) -> Self {
+ Self {
+ value,
+ _marker: Default::default(),
+ }
+ }
+}
+
+pub struct IntegerWalkerError<T> {
+ value: T,
+}
+
+impl<T: Integer> ::core::fmt::Debug for IntegerWalkerError<T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("IntegerWalkerError")
+ .field("value", &self.value)
+ .finish()
+ }
+}
+
+impl<T: Integer> ::core::fmt::Display for IntegerWalkerError<T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("IntegerWalkerError")
+ .field("value", &self.value)
+ .finish()
+ }
+}
+
+impl<'ctx, T: Integer, E: Effect> Walker<'ctx, E> for IntegerWalker<T, E> {
+ type Error = IntegerWalkerError<T>;
+
+ type Output = T;
+
+ fn walk<'visitor: 'effect, 'effect>(
+ self,
+ visitor: DynVisitor<'visitor, 'ctx>,
+ ) -> ErasedEffective<'effect, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'effect,
+ {
+ let value = self.value;
+
+ E::as_ctx((self, visitor), move |(this, visitor)| {
+ request_hint::<E>(visitor.cast(), DynWalker(this))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .map(|((_, visitor), result)| (visitor, result))
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, i8>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, u8>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, i16>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, u16>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, i32>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, u32>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, i64>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, u64>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, i128>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, u128>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, isize>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .if_skipped(move |visitor| {
+ if let Some(value) = try_into::<_, usize>(value) {
+ visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ } else {
+ E::ready(VisitResult::Skipped(())).cast()
+ }
+ })
+ .map(move |(_, result)| match result {
+ VisitResult::Skipped(()) => Err(IntegerWalkerError { value }),
+ VisitResult::Control(_) => Ok(value),
+ })
+ }
+}
+
+impl<T> Integer for T where
+ T: 'static
+ + Copy
+ + core::fmt::Debug
+ + core::fmt::Display
+ + Ss
+ + TryInto<u8>
+ + TryInto<u16>
+ + TryInto<u32>
+ + TryInto<u64>
+ + TryInto<u128>
+ + TryInto<usize>
+ + TryInto<i8>
+ + TryInto<i16>
+ + TryInto<i32>
+ + TryInto<i64>
+ + TryInto<i128>
+ + TryInto<isize>
+{
+}
+
+any_trait! {
+ impl['ctx, T, E] IntegerWalker<T, E> = [
+ HintProto<ValueProto<OwnedStatic<i8>, E>>,
+ HintProto<ValueProto<OwnedStatic<i16>, E>>,
+ HintProto<ValueProto<OwnedStatic<i32>, E>>,
+ HintProto<ValueProto<OwnedStatic<i64>, E>>,
+ HintProto<ValueProto<OwnedStatic<i128>, E>>,
+ HintProto<ValueProto<OwnedStatic<u8>, E>>,
+ HintProto<ValueProto<OwnedStatic<u16>, E>>,
+ HintProto<ValueProto<OwnedStatic<u32>, E>>,
+ HintProto<ValueProto<OwnedStatic<u64>, E>>,
+ HintProto<ValueProto<OwnedStatic<u128>, E>>,
+ ] where
+ T: Integer,
+ E: Effect
+}
+
+macro_rules! impl_hints {
+ ($($type:ty),* $(,)?) => {
+ $(impl<'ctx, T: Integer, E: Effect> Hint<'ctx, ValueProto<OwnedStatic<$type>, E>>
+ for IntegerWalker<T, E>
+ {
+ fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
+ &'this mut self,
+ visitor: DynVisitorWith<'visitor, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
+ _hint: MetaHint<'hint, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
+ ) -> ErasedEffective<'e, crate::protocol::visitor::VisitResult, E>
+ where
+ 'ctx: 'this + 'visitor + 'hint + 'e,
+ {
+ if let Some(value) = try_into::<_, $type>(self.value) {
+ visit_value::<_, E>(visitor.into_inner(), OwnedStatic(value))
+ .map(VisitResult::unit_skipped)
+ } else {
+ E::ready(VisitResult::Skipped(()))
+ }
+ }
+
+ fn known<'a>(
+ &'a mut self,
+ _hint: &'a MetaHint<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
+ ) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>, ()>, E>
+ {
+ E::ready(Ok(ValueKnown { preview: None }))
+ }
+ })*
+ };
+}
+
+impl_hints![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize];
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index e6138fb..f20ab0d 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -13,7 +13,7 @@ use crate::{
SequenceKnown, SequenceProto, SequenceScope, Tag, TagConst, TagDyn, TagError, TagKnown,
TagProto, Value, ValueKnown, ValueProto, VisitResult,
},
- walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown},
+ walker::hint::{DynVisitorWith, Hint, HintMeta, HintProto, MetaHint, MetaKnown},
DynVisitor, DynWalker,
},
DynWalkerAdapter, Flow, Status, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID,
@@ -186,9 +186,9 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Recoverable<'ctx, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, RecoverableProto<E>>,
_hint: MetaHint<'hint, 'ctx, RecoverableProto<E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -220,9 +220,13 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Tag<'ctx, tags::FieldNames, E> + Send + Sync),
+ _visitor: DynVisitorWith<
+ 'visitor,
+ 'ctx,
+ TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>,
+ >,
_hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -268,9 +272,9 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Tag<'ctx, tags::TypeName, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>,
_hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -316,9 +320,9 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Tag<'ctx, tags::Map, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>,
_hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -360,9 +364,9 @@ where
#[inline(always)]
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
- visitor: &'visitor mut (dyn Tag<'ctx, tags::Struct, E> + Send + Sync),
+ visitor: DynVisitorWith<'visitor, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>,
_hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -371,8 +375,9 @@ where
#[inline(always)]
|(visitor, noop_walker)| {
visitor
+ .as_known()
.visit(TagConst, noop_walker)
- .map(|status| status.to_flow().unwrap_or(Flow::Continue))
+ .map(|status| VisitResult::Control(status.to_flow().unwrap_or(Flow::Continue)))
.cast()
},
)
@@ -404,9 +409,9 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Tag<'ctx, tags::TypeId, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>,
_hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -452,9 +457,9 @@ where
#[inline(always)]
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Tag<'ctx, TagDyn, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, TagProto<TagDyn, E>>,
_hint: MetaHint<'hint, 'ctx, TagProto<TagDyn, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -520,9 +525,9 @@ where
#[inline(always)]
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- _visitor: &'visitor mut (dyn Value<'ctx, BorrowedStaticHrt<I::T>, E> + Send + Sync),
+ _visitor: DynVisitorWith<'visitor, 'ctx, ValueProto<BorrowedStaticHrt<I::T>, E>>,
_hint: MetaHint<'hint, 'ctx, ValueProto<BorrowedStaticHrt<I::T>, E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
@@ -554,18 +559,22 @@ where
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
- visitor: &'visitor mut (dyn Sequence<'ctx, E> + Send + Sync),
+ visitor: DynVisitorWith<'visitor, 'ctx, SequenceProto<E>>,
_hint: MetaHint<'hint, 'ctx, SequenceProto<E>>,
- ) -> ErasedEffective<'e, Flow, E>
+ ) -> ErasedEffective<'e, VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
E::as_ctx_map((self, visitor), |(this, visitor)| {
visitor
+ .as_known()
.visit(*this)
- .map(|status| match status {
- VisitResult::Skipped(_) => Flow::Continue,
- VisitResult::Control(flow) => flow,
+ .map(|status| {
+ match status {
+ VisitResult::Skipped(_) => Flow::Continue,
+ VisitResult::Control(flow) => flow,
+ }
+ .into()
})
.cast()
})
diff --git a/src/walk/walkers/serde/deserializer.rs b/src/walk/walkers/serde/deserializer.rs
index cabffab..f5d9628 100644
--- a/src/walk/walkers/serde/deserializer.rs
+++ b/src/walk/walkers/serde/deserializer.rs
@@ -1,15 +1,336 @@
-use crate::{effect::Effect, Walker};
+use serde::Deserializer;
-pub struct DeserializerWalker<T> {
- deserializer: T,
+use crate::{
+ any::{BorrowedStaticHrt, OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName}, any_trait, effect::{
+ BlockOn, Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss,
+ }, hkt::Marker, protocol::{
+ visitor::{request_hint, visit_value, ValueKnown, ValueProto, VisitResult},
+ walker::hint::{DynVisitorWith, Hint, HintMeta, HintProto, MetaHint, MetaKnown},
+ DynVisitor, DynWalker,
+ }, walkers::core::int::IntegerWalkerError, Flow, Walker
+};
+
+pub struct DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ inner: Inner<'ctx, T>,
+ _marker: Marker<E>,
+}
+
+enum Inner<'ctx, T>
+where
+ T: Deserializer<'ctx>,
+{
+ Temp,
+ Init(T),
+ Error(DeserializerWalkerError<'ctx, T>),
+ Done,
+}
+
+impl<'ctx, T, E: Effect> DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ pub fn new(deserializer: T) -> Self {
+ Self {
+ inner: Inner::Init(deserializer),
+ _marker: Default::default(),
+ }
+ }
+}
+
+pub struct DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ inner: VisitorError<'ctx, T>,
+}
+
+impl<'ctx, T> core::fmt::Debug for DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match &self.inner {
+ VisitorError::u8(err) => write!(f, "{}", err),
+ VisitorError::u16(err) => write!(f, "{}", err),
+ VisitorError::u32(err) => write!(f, "{}", err),
+ VisitorError::u64(err) => write!(f, "{}", err),
+ VisitorError::u128(err) => write!(f, "{}", err),
+ VisitorError::usize(err) => write!(f, "{}", err),
+ VisitorError::i8(err) => write!(f, "{}", err),
+ VisitorError::i16(err) => write!(f, "{}", err),
+ VisitorError::i32(err) => write!(f, "{}", err),
+ VisitorError::i64(err) => write!(f, "{}", err),
+ VisitorError::i128(err) => write!(f, "{}", err),
+ VisitorError::isize(err) => write!(f, "{}", err),
+ VisitorError::Serde(err) => write!(f, "{}", err),
+ }
+ }
+}
+
+impl<'ctx, T> core::fmt::Display for DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl<'ctx, T, E: Effect> Walker<'ctx, E> for DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx> + Ss,
+ T::Error: Ss,
+{
+ type Error = DeserializerWalkerError<'ctx, T>;
+
+ type Output = ();
+
+ fn walk<'visitor: 'effect, 'effect>(
+ self,
+ visitor: DynVisitor<'visitor, 'ctx>,
+ ) -> ErasedEffective<'effect, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'effect,
+ {
+ E::as_ctx((self, visitor), |(this, visitor)| {
+ // Serde deserializers usually prefer that a hint method is called rather than _any.
+ // As such we need to ask the visitor for a hint first.
+ request_hint::<E>(visitor.cast(), DynWalker(this))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .map(|((this, _), _)| match this.inner {
+ Inner::Temp => todo!(),
+ Inner::Init(_) => todo!(),
+ Inner::Error(err) => Err(err),
+ Inner::Done => Ok(()),
+ })
+ }
+}
+
+any_trait! {
+ impl['ctx, T, E] DeserializerWalker<'ctx, T, E> = [
+ HintProto<ValueProto<OwnedStatic<bool>, E>>,
+ HintProto<ValueProto<OwnedStatic<i8>, E>>,
+ HintProto<ValueProto<OwnedStatic<i16>, E>>,
+ HintProto<ValueProto<OwnedStatic<i32>, E>>,
+ HintProto<ValueProto<OwnedStatic<i64>, E>>,
+ HintProto<ValueProto<OwnedStatic<i128>, E>>,
+ HintProto<ValueProto<OwnedStatic<u8>, E>>,
+ HintProto<ValueProto<OwnedStatic<u16>, E>>,
+ HintProto<ValueProto<OwnedStatic<u32>, E>>,
+ HintProto<ValueProto<OwnedStatic<u64>, E>>,
+ HintProto<ValueProto<OwnedStatic<u128>, E>>,
+ HintProto<ValueProto<OwnedStatic<char>, E>>,
+ ] where
+ T: Deserializer<'ctx> + Ss,
+ T::Error: Ss,
+ E: Effect
+}
+
+impl<'ctx, T, E: Effect> DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ fn call_deserialize<'visitor, 'e, F>(&mut self, f: F) -> ErasedEffective<'e, VisitResult, E>
+ where
+ F: FnOnce(T) -> Result<(Option<VisitorError<'ctx, T>>, VisitResult), T::Error>,
+ {
+ match core::mem::replace(&mut self.inner, Inner::Temp) {
+ Inner::Init(deserializer) => {
+ match f(deserializer) {
+ Ok((None, result)) => {
+ // Return the flow the visitor decided on.
+ self.inner = Inner::Done;
+ E::ready(result)
+ }
+ Ok((Some(err), _)) => {
+ self.inner = Inner::Error(DeserializerWalkerError { inner: err});
+ E::ready(Flow::Err.into())
+ }
+ Err(err) => {
+ // There was an error from serde so record it and signal an error with the
+ // flow.
+ self.inner = Inner::Error(DeserializerWalkerError { inner: VisitorError::Serde(err) });
+ E::ready(Flow::Err.into())
+ }
+ }
+ }
+ inner => {
+ // We really shouldn't be in this situation...
+ self.inner = inner;
+ E::ready(VisitResult::Skipped(()))
+ }
+ }
+ }
+}
+
+macro_rules! impl_hints {
+ (<$ctx:lifetime, $T:ident, $E:ident> $($proto:ty => $method:ident: $type:ty),* $(,)?) => {
+ $(impl<$ctx, $T, $E: Effect> Hint<$ctx, $proto> for DeserializerWalker<$ctx, $T, $E>
+ where
+ $T: Deserializer<$ctx>,
+ {
+ fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
+ &'this mut self,
+ visitor: DynVisitorWith<'visitor, $ctx, $proto>,
+ _hint: MetaHint<'hint, $ctx, $proto>,
+ ) -> ErasedEffective<'e, VisitResult, $E>
+ where
+ $ctx: 'this + 'visitor + 'hint + 'e,
+ {
+ self.call_deserialize(|deserializer| deserializer.$method(Visitor::new(visitor, stringify!($type))))
+ }
+
+ fn known<'a>(
+ &'a mut self,
+ _hint: &'a MetaHint<'a, 'ctx, $proto>,
+ ) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, $proto>, ()>, $E> {
+ E::ready(Ok(ValueKnown { preview: None }))
+ }
+ })*
+ };
+}
+
+impl_hints! {
+ <'ctx, T, E>
+ ValueProto<OwnedStatic<bool>, E> => deserialize_bool: bool,
+ ValueProto<OwnedStatic<i8>, E> => deserialize_i8: i8,
+ ValueProto<OwnedStatic<i16>, E> => deserialize_i16: i16,
+ ValueProto<OwnedStatic<i32>, E> => deserialize_i32: i32,
+ ValueProto<OwnedStatic<i64>, E> => deserialize_i64: i64,
+ ValueProto<OwnedStatic<i128>, E> => deserialize_i128: i128,
+ ValueProto<OwnedStatic<u8>, E> => deserialize_u8: u8,
+ ValueProto<OwnedStatic<u16>, E> => deserialize_u16: u16,
+ ValueProto<OwnedStatic<u32>, E> => deserialize_u32: u32,
+ ValueProto<OwnedStatic<u64>, E> => deserialize_u64: u64,
+ ValueProto<OwnedStatic<u128>, E> => deserialize_u128: u128,
+ ValueProto<OwnedStatic<f32>, E> => deserialize_f32: f32,
+ ValueProto<OwnedStatic<f64>, E> => deserialize_f64: f64,
+ ValueProto<OwnedStatic<char>, E> => deserialize_char: char,
+ ValueProto<TempBorrowedStaticHrt<str>, E> => deserialize_str: &str,
+ ValueProto<BorrowedStaticHrt<str>, E> => deserialize_str: &str,
+ ValueProto<OwnedStatic<String>, E> => deserialize_string: String,
+ ValueProto<TempBorrowedStaticHrt<[u8]>, E> => deserialize_bytes: &[u8],
+ ValueProto<BorrowedStaticHrt<[u8]>, E> => deserialize_bytes: &[u8],
+ ValueProto<OwnedStatic<Vec<u8>>, E> => deserialize_byte_buf: Vec<u8>,
+ // ...
+}
+
+#[allow(non_camel_case_types, unused)]
+enum VisitorError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ u8(IntegerWalkerError<u8>),
+ u16(IntegerWalkerError<u16>),
+ u32(IntegerWalkerError<u32>),
+ u64(IntegerWalkerError<u64>),
+ u128(IntegerWalkerError<u128>),
+ usize(IntegerWalkerError<usize>),
+ i8(IntegerWalkerError<i8>),
+ i16(IntegerWalkerError<i16>),
+ i32(IntegerWalkerError<i32>),
+ i64(IntegerWalkerError<i64>),
+ i128(IntegerWalkerError<i128>),
+ isize(IntegerWalkerError<isize>),
+ Serde(T::Error),
+}
+
+struct Visitor<'temp, 'ctx, T, E>
+where
+ T: Deserializer<'ctx>
+{
+ wanted: &'static str,
+ visitor: DynVisitor<'temp, 'ctx>,
+ error: Option<VisitorError<'ctx, T>>,
+ _marker: Marker<(T, E)>,
+}
+
+impl<'temp, 'ctx, T, E> Visitor<'temp, 'ctx, T, E>
+where
+ T: Deserializer<'ctx>
+{
+ pub fn new<Protocol: HintMeta<Effect = E>>(
+ visitor: DynVisitorWith<'temp, 'ctx, Protocol>,
+ wanted: &'static str,
+ ) -> Self {
+ Self {
+ wanted,
+ visitor: visitor.into_inner(),
+ error: None,
+ _marker: Default::default(),
+ }
+ }
}
-// impl<'ctx, T, E: Effect> Walker<'ctx, E> for DeserializerWalker<T> {
-//
-// }
-//
-// impl<T> WalkerTypes for DeserializerWalker<T> {
-// type Error;
-//
-// type Output;
-// }
+macro_rules! impl_visits {
+ (@owned $($method:ident: $type:ty),* $(,)?) => {
+ $(fn $method<Err>(mut self, v: $type) -> Result<Self::Value, Err>
+ where
+ Err: serde::de::Error,
+ {
+ // Visit the treaty visitor with the value serde gave.
+ let result = visit_value::<_, E>(self.visitor.cast(), OwnedStatic(v));
+
+ // Because serde is sync we need to block on the effective here.
+ // We use the block on impl the effect context says to use.
+ let value = E::BlockOn::block_on(result.into_future());
+
+ // If the visitor skipped the value we just report a continue.
+ Ok((self.error, value.unit_skipped()))
+ })*
+ };
+ // Many serde deserializers (like serde_json) don't follow the hint given when visiting.
+ // So we need to use the full integer walker that can visit all the types.
+ (@int $($method:ident: $type:ident),* $(,)?) => {
+ $(fn $method<Err>(mut self, v: $type) -> Result<Self::Value, Err>
+ where
+ Err: serde::de::Error,
+ {
+ let result = $crate::walkers::core::int::IntegerWalker::<_, E>::new(v).walk(self.visitor.cast());
+
+ // Because serde is sync we need to block on the effective here.
+ // We use the block on impl the effect context says to use.
+ if let Err(err) = E::BlockOn::block_on(result.into_future()) {
+ self.error = Some(VisitorError::$type(err))
+ }
+
+ Ok((self.error, VisitResult::Control(Flow::Done)))
+ })*
+ };
+}
+
+impl<'temp, 'ctx, T: Deserializer<'ctx>, E: Effect> serde::de::Visitor<'ctx> for Visitor<'temp, 'ctx, T, E> {
+ type Value = (Option<VisitorError<'ctx, T>>, VisitResult);
+
+ fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ formatter.write_str(&self.wanted)
+ }
+
+ impl_visits! {
+ @owned
+ visit_bool: bool,
+ visit_char: char,
+ visit_string: String,
+ visit_byte_buf: Vec<u8>,
+ // ...
+ }
+
+ impl_visits! {
+ @int
+ visit_i8: i8,
+ visit_i16: i16,
+ visit_i32: i32,
+ visit_i64: i64,
+ visit_i128: i128,
+ visit_u8: u8,
+ visit_u16: u16,
+ visit_u32: u32,
+ visit_u64: u64,
+ visit_u128: u128,
+ }
+}
diff --git a/tests/builder_value.rs b/tests/builder_value.rs
index 9f52252..b1d36de 100644
--- a/tests/builder_value.rs
+++ b/tests/builder_value.rs
@@ -20,12 +20,15 @@ fn value_builder_gives_value_protocol_as_hint() {
// Expect the value builder to hint the value protocol with a owned i32.
let mut walker = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new();
- walker.expect_hint().once().returning(|visitor, ()| {
+ walker.expect_hint().once().returning(|mut visitor, ()| {
// Fulfill the hint by visiting with a i32 value.
- assert_eq!(visitor.visit(OwnedStatic(42)).value(), Flow::Done.into());
+ assert_eq!(
+ visitor.as_known().visit(OwnedStatic(42)).value(),
+ Flow::Done.into()
+ );
// We are done as the walker.
- Flow::Done
+ Flow::Done.into()
});
// Request a hint from the i32 builder for what protocol to use.
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index 5b35ce8..5c714e1 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -9,7 +9,7 @@ use std::{
sync::{Mutex, MutexGuard, OnceLock, RwLock},
};
-use treaty::effect::blocking::{BlockOn, Spin};
+use treaty::effect::blocking::Spin;
pub mod builder;
pub mod protocol;
diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs
index 1ca94dc..89f53a6 100644
--- a/tests/common/protocol/hint.rs
+++ b/tests/common/protocol/hint.rs
@@ -3,7 +3,8 @@ use treaty::{
any::{any_trait, TypeName},
effect::{Effect, Effective, ErasedEffective},
protocol::{
- walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown},
+ visitor::VisitResult,
+ walker::hint::{DynVisitorWith, Hint, HintMeta, HintProto, MetaHint, MetaKnown},
DynVisitor,
},
Flow,
@@ -14,7 +15,7 @@ pub type KnownFactory<P> =
mock! {
pub HintWalker<P: HintMeta> {
- pub fn hint<'a, 'b, 'c, 'ctx>(&'a mut self, visitor: &'b mut TypeName::T<'b, 'ctx, P>, hint: MetaHint<'c, 'ctx, P>) -> Flow;
+ pub fn hint<'a, 'b, 'c, 'ctx>(&'a mut self, visitor: DynVisitorWith<'b, 'ctx, P>, hint: MetaHint<'c, 'ctx, P>) -> VisitResult;
pub fn known(&self) -> KnownFactory<P>;
}
@@ -30,9 +31,9 @@ any_trait! {
impl<'ctx, P: HintMeta> Hint<'ctx, P> for MockHintWalker<P> {
fn hint<'this, 'visitor, 'hint, 'e>(
&'this mut self,
- visitor: &'visitor mut TypeName::T<'visitor, 'ctx, P>,
+ visitor: DynVisitorWith<'visitor, 'ctx, P>,
hint: MetaHint<'hint, 'ctx, P>,
- ) -> ErasedEffective<'e, Flow, P::Effect>
+ ) -> ErasedEffective<'e, VisitResult, P::Effect>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
diff --git a/tests/common/protocol/recoverable.rs b/tests/common/protocol/recoverable.rs
index 1ccce92..c338b09 100644
--- a/tests/common/protocol/recoverable.rs
+++ b/tests/common/protocol/recoverable.rs
@@ -16,15 +16,9 @@ use treaty::{
Flow, Status,
};
-pub type RecoverableScopeFactory<E> =
- for<'a, 'ctx> fn(
- &'ctx (),
- DynRecoverableScope<'a, 'ctx, E>,
- ) -> VisitResult<DynRecoverableScope<'a, 'ctx, E>>;
-
mock! {
pub RecoverableVisitor<E> {
- pub fn visit(&mut self) -> RecoverableScopeFactory<E>;
+ pub fn visit<'a, 'ctx>(&mut self, scope: DynRecoverableScope<'a, 'ctx, E>) -> VisitResult;
}
}
@@ -39,8 +33,8 @@ impl<'ctx, E: Effect> Recoverable<'ctx, E> for MockRecoverableVisitor<E> {
fn visit<'a>(
&'a mut self,
scope: DynRecoverableScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> {
- E::ready(self.visit()(&(), scope))
+ ) -> ErasedEffective<'a, VisitResult, E> {
+ E::ready(self.visit(scope))
}
}
diff --git a/tests/common/protocol/request_hint.rs b/tests/common/protocol/request_hint.rs
index dc57b5e..63c423d 100644
--- a/tests/common/protocol/request_hint.rs
+++ b/tests/common/protocol/request_hint.rs
@@ -7,12 +7,9 @@ use treaty::{
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;
+ pub fn request_hint<'a, 'ctx>(&mut self, walker: DynWalker<'a, 'ctx>) -> VisitResult;
}
}
@@ -24,10 +21,13 @@ any_trait! {
}
impl<'ctx, E: Effect> RequestHint<'ctx, E> for MockRequestHintVisitor<E> {
- fn request_hint<'a>(
- &'a mut self,
- walker: DynWalker<'a, 'ctx>,
- ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
- E::ready(self.request_hint()(&(), walker))
+ fn request_hint<'this: 'e, 'walker: 'e, 'e>(
+ &'this mut self,
+ walker: DynWalker<'walker, 'ctx>,
+ ) -> ErasedEffective<'e, VisitResult, E>
+ where
+ 'ctx: 'this + 'walker,
+ {
+ E::ready(self.request_hint(walker))
}
}
diff --git a/tests/common/protocol/sequence.rs b/tests/common/protocol/sequence.rs
index c7e68b1..43e71db 100644
--- a/tests/common/protocol/sequence.rs
+++ b/tests/common/protocol/sequence.rs
@@ -13,14 +13,9 @@ use treaty::{
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>;
+ pub fn visit<'a, 'ctx>(&mut self, scope: DynSequenceScope<'a, 'ctx, E>) -> VisitResult;
}
}
@@ -35,8 +30,8 @@ impl<'ctx, E: Effect> Sequence<'ctx, E> for MockSequenceVisitor<E> {
fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
scope: DynSequenceScope<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E> {
- E::ready(self.visit()(&(), scope))
+ ) -> ErasedEffective<'c, VisitResult, E> {
+ E::ready(self.visit(scope))
}
}
diff --git a/tests/common/protocol/tag.rs b/tests/common/protocol/tag.rs
index 2dcd805..890157e 100644
--- a/tests/common/protocol/tag.rs
+++ b/tests/common/protocol/tag.rs
@@ -8,7 +8,7 @@ use treaty::{
mock! {
pub TagVisitor<K: TagKind, E> {
- pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalkerObjSafe<'a, 'ctx, E>) -> VisitResult<()>;
+ pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalkerObjSafe<'a, 'ctx, E>) -> VisitResult;
}
}
@@ -25,10 +25,7 @@ impl<'ctx, K: TagKind, E: Effect> Tag<'ctx, K, E> for MockTagVisitor<K, E> {
&'a mut self,
kind: K,
walker: DynWalkerObjSafe<'b, 'ctx, E>,
- ) -> ErasedEffective<'c, VisitResult<DynWalkerObjSafe<'b, 'ctx, E>>, E> {
- E::ready(match self.visit(kind, walker) {
- VisitResult::Skipped(_) => VisitResult::Skipped(walker),
- VisitResult::Control(flow) => VisitResult::Control(flow),
- })
+ ) -> ErasedEffective<'c, VisitResult, E> {
+ E::ready(self.visit(kind, walker))
}
}
diff --git a/tests/protocol_visitor_recoverable.rs b/tests/protocol_visitor_recoverable.rs
index cde5ca1..2b8e6a1 100644
--- a/tests/protocol_visitor_recoverable.rs
+++ b/tests/protocol_visitor_recoverable.rs
@@ -9,10 +9,7 @@ use treaty::{
Flow, Status,
};
-use crate::common::{
- builder::MockBuilder,
- protocol::recoverable::{MockRecoverableScopeVisitor, RecoverableScopeFactory},
-};
+use crate::common::{builder::MockBuilder, protocol::recoverable::MockRecoverableScopeVisitor};
mod common;
@@ -22,23 +19,21 @@ fn recoverable_can_be_visited() {
let mut mock = MockRecoverableVisitor::<Blocking>::new();
// Expect a visit using the rescoverable protocol.
- mock.expect_visit().once().return_const(
- (|(), scope| {
- let mut visitor = MockBuilder::<(), (), ()>::new();
+ mock.expect_visit().once().returning(|scope| {
+ let mut visitor = MockBuilder::<(), (), ()>::new();
- // Expect that the visitor gets used.
- visitor.expect_traits().times(2).return_const(None);
+ // Expect that the visitor gets used.
+ visitor.expect_traits().times(2).return_const(None);
- // Attempt to walk once.
- assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
+ // Attempt to walk once.
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
- // Attempt to walk twice.
- assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
+ // Attempt to walk twice.
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
- // We are done.
- VisitResult::Control(Flow::Done)
- }) as RecoverableScopeFactory<Blocking>,
- );
+ // We are done.
+ VisitResult::Control(Flow::Done)
+ });
let visitor: &mut dyn Recoverable<Blocking> = &mut mock;
diff --git a/tests/protocol_visitor_request_hint.rs b/tests/protocol_visitor_request_hint.rs
index dee681d..098e24d 100644
--- a/tests/protocol_visitor_request_hint.rs
+++ b/tests/protocol_visitor_request_hint.rs
@@ -1,10 +1,7 @@
use std::any::TypeId;
use common::{
- protocol::{
- hint::MockHintWalker,
- request_hint::{MockRequestHintVisitor, RequestHintFactory},
- },
+ protocol::{hint::MockHintWalker, request_hint::MockRequestHintVisitor},
walker::MockWalker,
};
use mockall::predicate::eq;
@@ -28,25 +25,23 @@ 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(
- (|_, mut 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(&()).value(),
- Ok(ValueKnown {
- preview: Some(&OwnedStatic(42))
- })
- );
-
- // We are done.
- VisitResult::Control(Flow::Done)
- }) as RequestHintFactory,
- );
+ mock.expect_request_hint().once().returning(|mut 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(&()).value(),
+ Ok(ValueKnown {
+ preview: Some(&OwnedStatic(42))
+ })
+ );
+
+ // We are done.
+ VisitResult::Control(Flow::Done)
+ });
// This mock becomes the visitor.
let visitor: &mut dyn RequestHint<Blocking> = &mut mock;
diff --git a/tests/protocol_visitor_sequence.rs b/tests/protocol_visitor_sequence.rs
index 732e090..bc29ea4 100644
--- a/tests/protocol_visitor_sequence.rs
+++ b/tests/protocol_visitor_sequence.rs
@@ -1,6 +1,6 @@
use std::any::TypeId;
-use common::protocol::sequence::{MockSequenceScope, MockSequenceVisitor, SequenceScopeFactory};
+use common::protocol::sequence::{MockSequenceScope, MockSequenceVisitor};
use treaty::{
any::{OwnedStatic, TypeNameId},
effect::blocking::Blocking,
@@ -20,23 +20,21 @@ 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().value(), (1, Some(1)));
+ mock.expect_visit().once().returning(|scope| {
+ // Get the size hint from the sequence scope.
+ assert_eq!(scope.size_hint().value(), (1, Some(1)));
- let mut visitor = MockBuilder::<(), (), ()>::new();
+ let mut visitor = MockBuilder::<(), (), ()>::new();
- // Expect the walker to lookup a trait.
- visitor.expect_traits().once().return_const(None);
+ // Expect the walker to lookup a trait.
+ visitor.expect_traits().once().return_const(None);
- // Get the next item in the sequence from the walker.
- assert_eq!(scope.next(DynVisitor(&mut visitor)).value(), Flow::Done);
+ // Get the next item in the sequence from the walker.
+ assert_eq!(scope.next(DynVisitor(&mut visitor)).value(), Flow::Done);
- // We are done.
- VisitResult::Control(Flow::Done)
- }) as SequenceScopeFactory<Blocking>,
- );
+ // We are done.
+ VisitResult::Control(Flow::Done)
+ });
// Everything goes throw the sequence protocol trait.
let visitor: &mut dyn Sequence<Blocking> = &mut mock;
diff --git a/tests/serde_deserializer.rs b/tests/serde_deserializer.rs
new file mode 100644
index 0000000..4b7bc94
--- /dev/null
+++ b/tests/serde_deserializer.rs
@@ -0,0 +1,23 @@
+use serde_json::json;
+use treaty::walkers::serde::deserializer::DeserializerWalker;
+use treaty::BuildExt as _;
+
+mod common;
+
+#[test]
+fn demo() {
+ let x = json!(true);
+
+ let y = bool::build(DeserializerWalker::new(x));
+
+ assert!(y.unwrap());
+}
+
+#[test]
+fn demo2() {
+ let x = json!(42);
+
+ let y = u8::build(DeserializerWalker::new(x));
+
+ assert_eq!(y.unwrap(), 42);
+}
diff --git a/tests/walker_struct.rs b/tests/walker_struct.rs
index 6cb6e36..5898475 100644
--- a/tests/walker_struct.rs
+++ b/tests/walker_struct.rs
@@ -12,11 +12,7 @@ use treaty::{
use crate::common::{
builder::{EmptyError, MockBuilder},
- protocol::{
- sequence::{MockSequenceVisitor, SequenceScopeFactory},
- tag::MockTagVisitor,
- value::MockValueVisitor,
- },
+ protocol::{sequence::MockSequenceVisitor, tag::MockTagVisitor, value::MockValueVisitor},
};
mod common;
@@ -107,81 +103,78 @@ fn sequence_of_field_values() {
let mut visitor = MockSequenceVisitor::<Blocking>::new();
// Expect the sequence visitor to be used.
- visitor.expect_visit().once().return_const(
- (|_, scope| {
- // The struct should have exactly 2 fields.
- assert_eq!(scope.size_hint().value(), (2, Some(2)));
-
- // Get the first field value.
- {
- let mut visitor = MockBuilder::<(), (), EmptyError>::new();
-
- // Expect a bool value for the field.
- visitor
- .expect_traits_mut()
- .once()
- .with(eq(
- TypeNameId::of::<ValueProto<OwnedStatic<bool>, Blocking>>(),
- ))
- .returning(|_| {
- let mut visitor =
- MockValueVisitor::<OwnedStatic<bool>, Blocking>::new();
-
- // Expect true.
- visitor
- .expect_visit()
- .once()
- .with(eq(OwnedStatic(true)))
- .return_const(Flow::Done);
-
- Some(Box::new(visitor))
- });
-
- assert_eq!(
- scope
- .next(Builder::<Blocking>::as_visitor(&mut visitor))
- .value(),
- Flow::Continue
- );
- }
-
- // Get the second field value.
- {
- let mut visitor = MockBuilder::<(), (), EmptyError>::new();
-
- // Expect a i32 value.
- visitor
- .expect_traits_mut()
- .once()
- .with(eq(
- TypeNameId::of::<ValueProto<OwnedStatic<i32>, Blocking>>(),
- ))
- .returning(|_| {
- let mut visitor =
- MockValueVisitor::<OwnedStatic<i32>, Blocking>::new();
-
- // Expect a 42.
- visitor
- .expect_visit()
- .once()
- .with(eq(OwnedStatic(42)))
- .return_const(Flow::Done);
-
- Some(Box::new(visitor))
- });
-
- assert_eq!(
- scope
- .next(Builder::<Blocking>::as_visitor(&mut visitor))
- .value(),
- Flow::Done
- );
- }
-
- // We are done with the sequence of fields.
- VisitResult::Control(Flow::Done)
- }) as SequenceScopeFactory<Blocking>,
- );
+ visitor.expect_visit().once().returning(|scope| {
+ // The struct should have exactly 2 fields.
+ assert_eq!(scope.size_hint().value(), (2, Some(2)));
+
+ // Get the first field value.
+ {
+ let mut visitor = MockBuilder::<(), (), EmptyError>::new();
+
+ // Expect a bool value for the field.
+ visitor
+ .expect_traits_mut()
+ .once()
+ .with(eq(
+ TypeNameId::of::<ValueProto<OwnedStatic<bool>, Blocking>>(),
+ ))
+ .returning(|_| {
+ let mut visitor =
+ MockValueVisitor::<OwnedStatic<bool>, Blocking>::new();
+
+ // Expect true.
+ visitor
+ .expect_visit()
+ .once()
+ .with(eq(OwnedStatic(true)))
+ .return_const(Flow::Done);
+
+ Some(Box::new(visitor))
+ });
+
+ assert_eq!(
+ scope
+ .next(Builder::<Blocking>::as_visitor(&mut visitor))
+ .value(),
+ Flow::Continue
+ );
+ }
+
+ // Get the second field value.
+ {
+ let mut visitor = MockBuilder::<(), (), EmptyError>::new();
+
+ // Expect a i32 value.
+ visitor
+ .expect_traits_mut()
+ .once()
+ .with(eq(
+ TypeNameId::of::<ValueProto<OwnedStatic<i32>, Blocking>>(),
+ ))
+ .returning(|_| {
+ let mut visitor = MockValueVisitor::<OwnedStatic<i32>, Blocking>::new();
+
+ // Expect a 42.
+ visitor
+ .expect_visit()
+ .once()
+ .with(eq(OwnedStatic(42)))
+ .return_const(Flow::Done);
+
+ Some(Box::new(visitor))
+ });
+
+ assert_eq!(
+ scope
+ .next(Builder::<Blocking>::as_visitor(&mut visitor))
+ .value(),
+ Flow::Done
+ );
+ }
+
+ // We are done with the sequence of fields.
+ VisitResult::Control(Flow::Done)
+ });
Some(Box::new(visitor))
});