added tests for tuple and map like structs
Konnor Andrews 2024-04-22
parent de2bacf · commit 04d3e97
-rw-r--r--src/any.rs22
-rw-r--r--src/build/builders/core.rs17
-rw-r--r--src/build/builders/core/bool.rs2
-rw-r--r--src/build/builders/core/struct.rs285
-rw-r--r--src/build/builders/debug.rs8
-rw-r--r--src/effect.rs68
-rw-r--r--src/lib.rs16
-rw-r--r--src/protocol/visitor.rs22
-rw-r--r--src/protocol/visitor/tag.rs2
-rw-r--r--src/transform.rs1
-rw-r--r--src/walk/walkers/core/struct.rs115
-rw-r--r--tests/builder_struct.rs285
-rw-r--r--tests/common/mod.rs2
-rw-r--r--tests/common/protocol/sequence.rs4
-rw-r--r--tests/protocol_visitor_recoverable.rs14
-rw-r--r--tests/protocol_visitor_request_hint.rs6
-rw-r--r--tests/protocol_visitor_sequence.rs14
-rw-r--r--tests/protocol_visitor_tag.rs10
-rw-r--r--tests/protocol_visitor_value.rs31
-rw-r--r--tests/protocol_walker_hint.rs18
-rw-r--r--tests/walker_struct.rs42
21 files changed, 809 insertions, 175 deletions
diff --git a/src/any.rs b/src/any.rs
index 3ebc7b2..98fbf5c 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -226,10 +226,14 @@ impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + Sync + 'b {
macro_rules! any_trait {
{
impl[$lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?]
- else {
- let $id:ident;
+ else ref {
+ let ($this:ident, $id:ident);
$($fallback:tt)*
}
+ else mut {
+ let ($mut_this:ident, $mut_id:ident);
+ $($mut_fallback:tt)*
+ }
$(where $($bound:tt)*)?
} => {
impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name
@@ -250,6 +254,7 @@ macro_rules! any_trait {
$crate::any::TypeName::T<'__, $lt, $protocol>
>(self as _)),)*
$id => {
+ let $this = self;
$($fallback)*
}
}
@@ -269,8 +274,9 @@ macro_rules! any_trait {
=> ::core::option::Option::Some($crate::any::AnyTraitObject::<'__, $lt, _>::new::<
$crate::any::TypeName::T<'__, $lt, $protocol>
>(self as _)),)*
- $id => {
- $($fallback)*
+ $mut_id => {
+ let $mut_this = self;
+ $($mut_fallback)*
}
}
}
@@ -282,9 +288,13 @@ macro_rules! any_trait {
} => {
$crate::any::any_trait! {
impl[$lt $($generic)*] $name = [$($protocol),*]
- else {
+ else ref {
+ // Always answer no in the fallback branch if no fallback was given.
+ let (_this, _id);
+ ::core::option::Option::None
+ } else mut {
// Always answer no in the fallback branch if no fallback was given.
- let _id;
+ let (_this, _id);
::core::option::Option::None
} $(where $($bound)*)?
}
diff --git a/src/build/builders/core.rs b/src/build/builders/core.rs
index f983601..41cffcb 100644
--- a/src/build/builders/core.rs
+++ b/src/build/builders/core.rs
@@ -1,6 +1,23 @@
+use crate::any_trait;
+
// pub mod array;
pub mod bool;
// pub mod option;
// pub mod variant;
+pub mod r#struct;
pub mod tag_name;
+
+#[derive(Default)]
+#[non_exhaustive]
+pub struct NoopVisitor;
+
+impl NoopVisitor {
+ pub fn new() -> Self {
+ Self
+ }
+}
+
+any_trait! {
+ impl['ctx] NoopVisitor = []
+}
diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs
index 29b6ab0..bc2706d 100644
--- a/src/build/builders/core/bool.rs
+++ b/src/build/builders/core/bool.rs
@@ -75,6 +75,6 @@ impl<'ctx, E: Effect> Value<'ctx, OwnedStatic<bool>, E> for Builder<E> {
'ctx: 'a,
{
self.0 = Some(value);
- E::ready(Flow::Continue.into())
+ E::ready(Flow::Done.into())
}
}
diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs
new file mode 100644
index 0000000..cff1ab3
--- /dev/null
+++ b/src/build/builders/core/struct.rs
@@ -0,0 +1,285 @@
+use crate::{
+ any::{OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName},
+ any_trait,
+ effect::{Effect, Future},
+ hkt::Marker,
+ protocol::{
+ visitor::{
+ tags, DynSequenceScope, Sequence, SequenceProto, Tag, TagProto, Value, ValueProto,
+ VisitResult,
+ },
+ DynVisitor,
+ },
+ Builder, BuilderTypes, DynWalkerObjSafe, Flow,
+};
+
+use super::NoopVisitor;
+
+enum StructMode {
+ /// A tuple-like struct uses the order of the sequence.
+ Tuple,
+
+ /// A map-like struct uses field names.
+ Map,
+}
+
+pub struct StructBuilder<'ctx, I: StructTypeInfo<'ctx, M, E>, M, E: Effect> {
+ builders: I::Builders,
+ mode: StructMode,
+ _generics: Marker<E>,
+}
+
+pub trait StructTypeInfo<'ctx, M, E: Effect>: 'static {
+ type Builders: Send + Sync;
+
+ type Seed: Send + Sync;
+
+ type FieldMarker: Send + Sync + Copy;
+
+ type Error: Send + Sync;
+
+ type T: Send + Sync;
+
+ fn new_builders<'a>(seed: Self::Seed) -> Future<'a, Self::Builders, E>;
+
+ fn from_builders<'a>(builders: Self::Builders) -> Future<'a, Result<Self::T, Self::Error>, E>;
+
+ fn as_visitor<'a>(
+ marker: Self::FieldMarker,
+ builders: &'a mut Self::Builders,
+ ) -> DynVisitor<'a, 'ctx>;
+
+ fn marker_from_index(index: usize) -> Option<Self::FieldMarker>;
+ fn marker_from_name(name: &str) -> Option<Self::FieldMarker>;
+}
+
+impl<'ctx, I, M, E: Effect> BuilderTypes for StructBuilder<'ctx, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M, E>,
+{
+ type Seed = I::Seed;
+
+ type Error = ();
+
+ type Value = I::T;
+}
+
+impl<'ctx, I, M, E> Builder<'ctx, E> for StructBuilder<'ctx, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M, E>,
+ E: Effect,
+{
+ fn from_seed<'a>(seed: Self::Seed) -> Future<'a, Self, E>
+ where
+ Self: 'a,
+ {
+ E::wrap(async {
+ Self {
+ builders: I::new_builders(seed).await,
+ // Start in tuple mode until a struct or map tag is visited.
+ mode: StructMode::Tuple,
+ _generics: Default::default(),
+ }
+ })
+ }
+
+ fn build<'a>(self) -> Future<'a, Result<Self::Value, Self::Error>, E>
+ where
+ Self: 'a,
+ {
+ E::wrap(async {
+ match I::from_builders(self.builders).await {
+ Ok(value) => Ok(value),
+ Err(_) => todo!(),
+ }
+ })
+ }
+
+ fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
+ DynVisitor(self)
+ }
+}
+
+any_trait! {
+ impl['ctx, I, M, E] StructBuilder<'ctx, I, M, E> = [
+ TagProto<tags::Map, E>,
+ SequenceProto<E>
+ ] where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+}
+
+impl<'ctx, I, M, E> Tag<'ctx, tags::Map, E> for StructBuilder<'ctx, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M, E>,
+ E: Effect,
+{
+ fn visit<'a>(
+ &'a mut self,
+ _kind: tags::Map,
+ walker: DynWalkerObjSafe<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> {
+ // This signals to go into map mode for the sequence.
+ self.mode = StructMode::Map;
+
+ E::wrap(async {
+ walker
+ .walk(DynVisitor(&mut NoopVisitor::new()))
+ .await
+ .to_continue()
+ .into()
+ })
+ }
+}
+
+// A struct is a sequence of field values.
+impl<'ctx, I, M, E> Sequence<'ctx, E> for StructBuilder<'ctx, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M, E>,
+ E: Effect,
+{
+ fn visit<'a>(
+ &'a mut self,
+ scope: DynSequenceScope<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
+ match self.mode {
+ StructMode::Tuple => E::wrap(async {
+ let mut index = 0;
+
+ // For each index based marker.
+ while let Some(marker) = I::marker_from_index(index) {
+ // Select the visitor for this field.
+ let visitor = I::as_visitor(marker, &mut self.builders);
+
+ // Get the next value in the sequence.
+ match scope.next(visitor).await {
+ Flow::Continue => {}
+ Flow::Err => return VisitResult::Control(Flow::Err),
+ Flow::Done => break,
+ }
+
+ // Move to the next field.
+ index += 1;
+ }
+
+ VisitResult::Control(Flow::Done)
+ }),
+ StructMode::Map => E::wrap(async {
+ loop {
+ let mut visitor = FieldVisitor::<I, M, E> {
+ builders: &mut self.builders,
+ marker: None,
+ _marker: Default::default(),
+ };
+
+ match scope.next(DynVisitor(&mut visitor)).await {
+ Flow::Continue => {}
+ Flow::Err => return VisitResult::Control(Flow::Err),
+ Flow::Done => return VisitResult::Control(Flow::Done),
+ }
+ }
+ }),
+ }
+ }
+}
+
+struct FieldVisitor<'a, 'ctx, I: StructTypeInfo<'ctx, M, E>, M, E: Effect> {
+ builders: &'a mut I::Builders,
+ marker: Option<I::FieldMarker>,
+ _marker: Marker<E>,
+}
+
+any_trait! {
+ impl['ctx, 'a, I, M, E] FieldVisitor<'a, 'ctx, I, M, E> = [
+ TagProto<tags::Key, E>,
+ ] else ref {
+ let (_this, _id);
+ None
+ } else mut {
+ let (this, id);
+
+ this.marker.and_then(|marker| {
+ I::as_visitor(marker, this.builders).0.upcast_to_id_mut(id)
+ })
+ } where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+}
+
+impl<'b, 'ctx, I, M, E> Tag<'ctx, tags::Key, E> for FieldVisitor<'b, 'ctx, I, M, E>
+where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+{
+ fn visit<'a>(
+ &'a mut self,
+ _key: tags::Key,
+ walker: DynWalkerObjSafe<'a, 'ctx, E>,
+ ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> {
+ E::wrap(async {
+ let mut visitor = NameVisitor::<I, M, E> {
+ field_marker: None,
+ _marker: Default::default(),
+ };
+
+ let flow = walker.walk(DynVisitor(&mut visitor)).await;
+
+ self.marker = visitor.field_marker;
+
+ // We are expecting the value of the field to be given next.
+ flow.to_continue().into()
+ })
+ }
+}
+
+struct NameVisitor<'ctx, I: StructTypeInfo<'ctx, M, E>, M, E: Effect> {
+ field_marker: Option<I::FieldMarker>,
+ _marker: Marker<E>,
+}
+
+any_trait! {
+ impl['ctx, I, M, E] NameVisitor<'ctx, I, M, E> = [
+ ValueProto<OwnedStatic<usize>, E>,
+ ValueProto<TempBorrowedStaticHrt<str>, E>,
+ ] where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+}
+
+impl<'ctx, I, M, E> Value<'ctx, OwnedStatic<usize>, E> for NameVisitor<'ctx, I, M, E>
+where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+{
+ fn visit<'a>(
+ &'a mut self,
+ OwnedStatic(index): TypeName::T<'a, 'ctx, OwnedStatic<usize>>,
+ ) -> Future<'a, VisitResult<TypeName::T<'a, 'ctx, OwnedStatic<usize>>>, E>
+ where
+ TypeName::T<'a, 'ctx, OwnedStatic<usize>>: Send + Sized,
+ 'ctx: 'a,
+ {
+ self.field_marker = I::marker_from_index(index);
+
+ E::ready(VisitResult::Control(Flow::Done))
+ }
+}
+
+impl<'ctx, I, M, E> Value<'ctx, TempBorrowedStaticHrt<str>, E> for NameVisitor<'ctx, I, M, E>
+where
+ E: Effect,
+ I: StructTypeInfo<'ctx, M, E>,
+{
+ fn visit<'a>(
+ &'a mut self,
+ TempBorrowedStatic(name): TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>>,
+ ) -> Future<'a, VisitResult<TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>>>, E>
+ where
+ TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>>: Send + Sized,
+ 'ctx: 'a,
+ {
+ self.field_marker = I::marker_from_name(name);
+
+ E::ready(VisitResult::Control(Flow::Done))
+ }
+}
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs
index b0b8003..0d4e58d 100644
--- a/src/build/builders/debug.rs
+++ b/src/build/builders/debug.rs
@@ -29,8 +29,12 @@ any_trait! {
ValueProto<OwnedStatic<bool>, E>,
// DynValue<'a, 'ctx, OwnedStatic<&'static [&'static str]>, E>,
SequenceProto<E>,
- ] else {
- let id;
+ ] else ref {
+ let (_this, id);
+ println!("Unknown trait: {:?}", id);
+ None
+ } else mut {
+ let (_this, id);
println!("Unknown trait: {:?}", id);
None
} where E: Effect
diff --git a/src/effect.rs b/src/effect.rs
index cf8cbdd..920ee0e 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -60,6 +60,16 @@ pub struct Blocking<B = Spin> {
_marker: PhantomData<fn() -> B>,
}
+pub trait ReadyValue: core::future::Future {
+ fn value(self) -> Self::Output;
+}
+
+impl<T: Send> ReadyValue for core::future::Ready<T> {
+ fn value(self) -> Self::Output {
+ Spin::block_on(self)
+ }
+}
+
pub trait BlockOn: 'static {
fn block_on<F>(future: F) -> F::Output
where
@@ -106,36 +116,36 @@ pub fn noop() -> Waker {
unsafe { Waker::from_raw(RAW) }
}
-pub struct Ready<Output> {
- pub value: Option<Output>,
-}
-
-impl<Output> Ready<Output> {
- pub fn into_inner(self) -> Output {
- self.value.expect("`into_inner` called after completion")
- }
-}
-
-impl<Output> Unpin for Ready<Output> {}
-
-impl<Output> core::future::Future for Ready<Output> {
- type Output = Output;
-
- fn poll(mut self: core::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
- Poll::Ready(self.value.take().expect("`Ready` polled after completion"))
- }
-}
+// pub struct Ready<Output> {
+// pub value: Option<Output>,
+// }
+//
+// impl<Output> Ready<Output> {
+// pub fn into_inner(self) -> Output {
+// self.value.expect("`into_inner` called after completion")
+// }
+// }
+//
+// impl<Output> Unpin for Ready<Output> {}
+//
+// impl<Output> core::future::Future for Ready<Output> {
+// type Output = Output;
+//
+// fn poll(mut self: core::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+// Poll::Ready(self.value.take().expect("`Ready` polled after completion"))
+// }
+// }
higher_ranked_type! {
impl SendFuture {
- impl['a, Output] type T['a, Output] for Ready<Output> =
- Ready<Output>
+ impl['a, Output] type T['a, Output] for core::future::Ready<Output> =
+ core::future::Ready<Output>
where {
Output: Send
};
- impl['a, Output] type HigherRanked['a, Output] for Ready<Output> =
- Ready<Output>
+ impl['a, Output] type HigherRanked['a, Output] for core::future::Ready<Output> =
+ core::future::Ready<Output>
where {
Output: Send
};
@@ -143,20 +153,18 @@ higher_ranked_type! {
}
impl<B: BlockOn> Effect for Blocking<B> {
- type Future<T: Send> = Ready<T>;
+ type Future<T: Send> = core::future::Ready<T>;
fn wrap<'a, F>(future: F) -> SendFuture::T<'a, F::Output, Self::Future<F::Output>>
where
F: core::future::Future + Send + 'a,
<F as core::future::Future>::Output: Send,
{
- Ready {
- value: Some(B::block_on(future)),
- }
+ core::future::ready(B::block_on(future))
}
fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, T, Self::Future<T>> {
- Ready { value: Some(value) }
+ core::future::ready(value)
}
fn map<'a, T, U, F>(
@@ -169,9 +177,7 @@ impl<B: BlockOn> Effect for Blocking<B> {
F: FnOnce(T) -> U + Send + 'a,
{
let value = B::block_on(future);
- Ready {
- value: Some(func(value)),
- }
+ core::future::ready(func(value))
}
}
diff --git a/src/lib.rs b/src/lib.rs
index fe4d9da..aa77edd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -67,6 +67,22 @@ pub enum Flow {
Done,
}
+impl Flow {
+ pub fn to_done(self) -> Self {
+ match self {
+ Flow::Continue | Flow::Done => Flow::Done,
+ Flow::Err => Flow::Err,
+ }
+ }
+
+ pub fn to_continue(self) -> Self {
+ match self {
+ Flow::Continue | Flow::Done => Flow::Continue,
+ Flow::Err => Flow::Err,
+ }
+ }
+}
+
#[macro_export]
macro_rules! Walk {
{
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs
index ecb48d1..fbcfdd2 100644
--- a/src/protocol/visitor.rs
+++ b/src/protocol/visitor.rs
@@ -12,7 +12,8 @@ pub use sequence::*;
pub use tag::*;
pub use value::*;
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Copy, Clone)]
+#[must_use]
pub enum VisitResult<S> {
/// The protocol was not used.
///
@@ -24,6 +25,25 @@ pub enum VisitResult<S> {
Control(Flow),
}
+impl<S> PartialEq for VisitResult<S> {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Self::Skipped(_), Self::Skipped(_)) => true,
+ (Self::Control(l0), Self::Control(r0)) => l0 == r0,
+ _ => false,
+ }
+ }
+}
+
+impl<S> core::fmt::Debug for VisitResult<S> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match self {
+ Self::Skipped(_) => f.debug_tuple("Skipped").finish(),
+ Self::Control(arg0) => f.debug_tuple("Control").field(arg0).finish(),
+ }
+ }
+}
+
impl<S> From<Flow> for VisitResult<S> {
fn from(value: Flow) -> Self {
Self::Control(value)
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 0608381..806f4aa 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -18,6 +18,8 @@ pub mod tags {
pub type Struct = TagConst<{ Symbol::new("Struct").to_int() }>;
pub type Map = TagConst<{ Symbol::new("Map").to_int() }>;
+ pub type Key = TagConst<{ Symbol::new("Key").to_int() }>;
+ pub type Value = TagConst<{ Symbol::new("Value").to_int() }>;
}
pub trait TagKind: Copy + Send + Sync + 'static {
diff --git a/src/transform.rs b/src/transform.rs
index edfa92a..81bcf47 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -32,6 +32,7 @@ pub struct Projection<T, B, U, M> {
_marker: Marker<(U, M)>,
}
+#[allow(clippy::type_complexity)]
impl<T, B, U: Send + Sync, M> Projection<T, B, U, M> {
pub fn project_ref<'a, E: Effect>(
&'a self,
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index 2cb4c14..9e67382 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -1,7 +1,7 @@
use core::any::TypeId;
use crate::{
- any::{BorrowedStatic, BorrowedStaticHrt},
+ any::{AnyTrait, BorrowedStatic, BorrowedStaticHrt},
any_trait,
effect::{Effect, Future},
hkt::Marker,
@@ -22,12 +22,16 @@ use crate::{
use super::{noop::NoopWalker, tag::StaticSliceWalker, value::ValueWalker};
+pub enum StaticType {}
+pub enum NamedType {}
+pub enum LifetimeType {}
+
/// Walker for a borrow of a struct.
///
/// This walker implements the struct flow. The struct cannot contain lifetimes.
-pub struct StructWalker<'ctx, T, I: StructTypeInfo<'ctx, M>, M, E> {
+pub struct StructWalker<'ctx, I: StructTypeInfo<'ctx, M, S = S>, S, M, E> {
/// Struct value to walk.
- value: &'ctx T,
+ value: &'ctx I::T,
/// Index of the current field to walk.
index: usize,
@@ -37,7 +41,7 @@ pub struct StructWalker<'ctx, T, I: StructTypeInfo<'ctx, M>, M, E> {
/// The visitor tracks it's own errors.
error: Option<StructWalkErrorKind<I::FieldError>>,
- _generics: Marker<(I, M, E)>,
+ _generics: Marker<E>,
}
/// Type info about a struct needed by [`StructWalker`].
@@ -51,6 +55,8 @@ pub trait StructTypeInfo<'ctx, M>: 'static {
/// The walking errors for the fields.
type FieldError: Send + Sync;
+ type S: 'static;
+
/// The struct being described.
type T: Send + Sync;
@@ -86,12 +92,12 @@ pub struct StructWalkError<T> {
kind: StructWalkErrorKind<T>,
}
-impl<'ctx, T, I, M, E> StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> StructWalker<'ctx, I, S, M, E>
where
- I: StructTypeInfo<'ctx, M>,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
/// Create walker from a borrow of a struct.
- pub fn new(value: &'ctx T) -> Self {
+ pub fn new(value: &'ctx I::T) -> Self {
Self {
value,
index: 0,
@@ -101,19 +107,19 @@ where
}
}
-impl<'ctx, T, I, M, E> WalkerTypes for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> WalkerTypes for StructWalker<'ctx, I, S, M, E>
where
- I: StructTypeInfo<'ctx, M>,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
type Error = StructWalkError<I::FieldError>;
type Output = ();
}
-impl<'ctx, T, I, E, M> crate::Walker<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, E, M> crate::Walker<'ctx, E> for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M, T = T>,
- T: Send + Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
+ Self: AnyTrait<'ctx> + RecoverableScope<'ctx, E>,
{
fn walk<'a>(
mut self,
@@ -136,10 +142,10 @@ where
}
any_trait! {
- impl['ctx, T, I, M, E] StructWalker<'ctx, T, I, M, E> = [
+ impl['ctx, I, M, E] StructWalker<'ctx, I, StaticType, M, E> = [
HintProto<RecoverableProto<E>>,
HintProto<SequenceProto<E>>,
- HintProto<ValueProto<BorrowedStaticHrt<T>, E>>,
+ HintProto<ValueProto<BorrowedStaticHrt<I::T>, E>>,
HintProto<TagProto<TagDyn, E>>,
HintProto<TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>,
HintProto<TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>,
@@ -148,15 +154,15 @@ any_trait! {
HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>,
] where
E: Effect,
- T: Send + Sync + 'static,
- I: StructTypeInfo<'ctx, M, T = T>
+ I: StructTypeInfo<'ctx, M, S = StaticType>,
+ I::T: 'static
}
-impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, RecoverableProto<E>> for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M, T = T>,
- T: Send + Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
+ Self: AnyTrait<'ctx> + RecoverableScope<'ctx, E>,
{
fn hint<'a>(
&'a mut self,
@@ -180,12 +186,11 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>
+ for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn hint<'a>(
&'a mut self,
@@ -223,12 +228,11 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>
+ for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn hint<'a>(
&'a mut self,
@@ -266,12 +270,11 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>
+ for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn hint<'a>(
&'a mut self,
@@ -302,12 +305,11 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>
+ for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn hint<'a>(
&'a mut self,
@@ -345,12 +347,12 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>
+ for StructWalker<'ctx, I, StaticType, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = StaticType>,
+ I::T: 'static,
{
fn hint<'a>(
&'a mut self,
@@ -361,7 +363,7 @@ where
visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
TagConst,
visitor,
- ValueWalker::new(TypeId::of::<T>()),
+ ValueWalker::new(TypeId::of::<I::T>()),
),
|status| match status {
Err(err) => {
@@ -388,11 +390,11 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagDyn, E>> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, M, E> Hint<'ctx, TagProto<TagDyn, E>> for StructWalker<'ctx, I, StaticType, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = StaticType>,
+ I::T: 'static,
{
fn hint<'a>(
&'a mut self,
@@ -449,12 +451,12 @@ where
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>>
- for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<I::T>, E>>
+ for StructWalker<'ctx, I, StaticType, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M>,
- T: Send + Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = StaticType>,
+ I::T: 'static,
{
fn hint<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> {
E::map(
@@ -469,16 +471,15 @@ where
fn known<'a>(
&'a mut self,
_hint: &'a (),
- ) -> Future<'a, Result<ValueKnown<'a, BorrowedStatic<'ctx, T>>, ()>, E> {
+ ) -> Future<'a, Result<ValueKnown<'a, BorrowedStatic<'ctx, I::T>>, ()>, E> {
E::ready(Ok(ValueKnown { preview: None }))
}
}
-impl<'ctx, T, I, M, E> Hint<'ctx, SequenceProto<E>> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> Hint<'ctx, SequenceProto<E>> for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M, T = T>,
- T: Sync,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn hint<'a>(
&'a mut self,
@@ -503,10 +504,10 @@ where
}
}
-impl<'ctx, T, I, M, E> SequenceScope<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, S, M, E> SequenceScope<'ctx, E> for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M, T = T>,
+ I: StructTypeInfo<'ctx, M, S = S>,
{
fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E> {
let len = I::FIELDS.len();
@@ -536,11 +537,11 @@ where
}
}
-impl<'ctx, T, I, M, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+impl<'ctx, I, M, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, I, StaticType, M, E>
where
E: Effect,
- I: StructTypeInfo<'ctx, M, T = T>,
- T: Send + Sync + 'static,
+ I: StructTypeInfo<'ctx, M, S = StaticType>,
+ I::T: 'static,
{
fn new_walk<'a>(&'a mut self, mut visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E> {
// Reset the errors to default state.
@@ -574,7 +575,7 @@ where
match visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
TagConst,
visitor.cast(),
- ValueWalker::new(TypeId::of::<T>()),
+ ValueWalker::new(TypeId::of::<I::T>()),
)
.await
{
diff --git a/tests/builder_struct.rs b/tests/builder_struct.rs
new file mode 100644
index 0000000..af56538
--- /dev/null
+++ b/tests/builder_struct.rs
@@ -0,0 +1,285 @@
+use treaty::{
+ any::{OwnedStatic, TempBorrowedStatic},
+ builders::{self, core::r#struct::StructBuilder},
+ effect::{Blocking, Effect, Future, ReadyValue},
+ protocol::{
+ visitor::{tags, visit_sequence, visit_tag, visit_value, TagConst, VisitResult},
+ DynVisitor,
+ },
+ transform,
+ walkers::{
+ self,
+ core::{
+ noop::NoopWalker,
+ r#struct::{StaticType, StructWalker},
+ },
+ },
+ Build, Builder, DefaultMode, Flow, Walk, Walker,
+};
+
+use crate::common::{
+ protocol::sequence::MockSequenceScope,
+ walker::MockWalker,
+};
+
+mod common;
+
+#[derive(Debug, PartialEq)]
+struct X {
+ a: bool,
+ b: bool,
+}
+
+struct Info;
+
+impl<'ctx, M> walkers::core::r#struct::StructTypeInfo<'ctx, M> for Info {
+ const NAME: &'static str = "X";
+
+ const FIELDS: &'static [&'static str] = &["a", "b"];
+
+ type FieldError = ();
+
+ type S = StaticType;
+
+ type T = X;
+
+ fn walk_field<'a, E: Effect>(
+ index: usize,
+ value: &'ctx Self::T,
+ visitor: DynVisitor<'a, 'ctx>,
+ ) -> Future<'a, Result<Flow, Self::FieldError>, E> {
+ E::wrap(async move {
+ match index {
+ 0 => {
+ let walker = <&bool as Walk<M, E>>::into_walker(&value.a);
+
+ assert_eq!(Walker::<E>::walk(walker, visitor).await, Ok(()));
+
+ Ok(Flow::Continue)
+ }
+ 1 => {
+ let walker = <&bool as Walk<M, E>>::into_walker(&value.b);
+
+ assert_eq!(Walker::<E>::walk(walker, visitor).await, Ok(()));
+
+ Ok(Flow::Continue)
+ }
+ _ => Ok(Flow::Done),
+ }
+ })
+ }
+}
+
+struct Fields<'ctx, M, E: Effect> {
+ a: <bool as Build<'ctx, M, E>>::Builder,
+ b: <bool as Build<'ctx, M, E>>::Builder,
+}
+
+#[derive(Copy, Clone)]
+enum FieldMarker {
+ A,
+ B,
+}
+
+impl<'ctx, M, E: Effect> builders::core::r#struct::StructTypeInfo<'ctx, M, E> for Info {
+ type Builders = Fields<'ctx, M, E>;
+
+ type FieldMarker = FieldMarker;
+
+ type T = X;
+
+ fn marker_from_index(index: usize) -> Option<Self::FieldMarker> {
+ match index {
+ 0 => Some(FieldMarker::A),
+ 1 => Some(FieldMarker::B),
+ _ => None,
+ }
+ }
+
+ fn marker_from_name(name: &str) -> Option<Self::FieldMarker> {
+ match name {
+ "a" => Some(FieldMarker::A),
+ "b" => Some(FieldMarker::B),
+ _ => None,
+ }
+ }
+
+ type Error = ();
+
+ fn from_builders<'a>(builders: Self::Builders) -> Future<'a, Result<Self::T, Self::Error>, E> {
+ E::wrap(async {
+ Ok(X {
+ a: builders.a.build().await.unwrap(),
+ b: builders.b.build().await.unwrap(),
+ })
+ })
+ }
+
+ fn as_visitor<'a>(
+ marker: Self::FieldMarker,
+ builders: &'a mut Self::Builders,
+ ) -> DynVisitor<'a, 'ctx> {
+ match marker {
+ FieldMarker::A => builders.a.as_visitor(),
+ FieldMarker::B => builders.b.as_visitor(),
+ }
+ }
+
+ type Seed = ();
+
+ fn new_builders<'a>(_seed: Self::Seed) -> Future<'a, Self::Builders, E> {
+ E::wrap(async {
+ Fields {
+ a: Builder::<E>::from_seed(()).await,
+ b: Builder::<E>::from_seed(()).await,
+ }
+ })
+ }
+}
+
+#[test]
+#[ignore]
+fn demo() {
+ let value = X { a: true, b: false };
+
+ let (other, _) = transform::<StructBuilder<Info, DefaultMode, _>, _, Blocking>(
+ (),
+ StructWalker::<Info, _, DefaultMode, _>::new(&value),
+ )
+ .value();
+
+ assert_eq!(other.unwrap(), value);
+}
+
+#[test]
+fn from_basic_tuple_like() {
+ // A tuple like is just a sequence.
+ let mut scope = MockSequenceScope::<Blocking>::new();
+
+ // First field.
+ scope.expect_next().once().returning(|visitor| {
+ // Visit a bool value.
+ //
+ // The bool visitor should report that it is done.
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, OwnedStatic(true)).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ // We have another field.
+ Flow::Continue
+ });
+
+ // Second field.
+ scope.expect_next().once().returning(|visitor| {
+ // Visit a bool value.
+ //
+ // The bool visitor should report that it is done.
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, OwnedStatic(false)).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ // No more fields.
+ Flow::Done
+ });
+
+ let mut builder = StructBuilder::<Info, DefaultMode, Blocking>::from_seed(()).value();
+ let visitor = builder.as_visitor();
+
+ // Visit the sequence of field values.
+ assert!(matches!(
+ visit_sequence(visitor, &mut scope).value(),
+ VisitResult::Control(Flow::Done)
+ ));
+
+ assert_eq!(builder.build().value().unwrap(), X { a: true, b: false });
+}
+
+#[test]
+fn from_basic_map_like() {
+ // A map is built from a sequence.
+ let mut scope = MockSequenceScope::<Blocking>::new();
+
+ // Here we do the b field first to show a map-like doesn't care about order.
+ scope.expect_next().once().returning(|mut visitor| {
+ let mut walker = MockWalker::<(), ()>::new();
+
+ // We need to give the b field name in the key tag.
+ walker.expect_walk().once().returning(|visitor| {
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, TempBorrowedStatic("b")).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ Ok(())
+ });
+
+ // Tag the value with a key as the field name.
+ assert_eq!(
+ visit_tag::<tags::Key, Blocking, _>(TagConst, visitor.cast(), walker).value(),
+ Ok(VisitResult::Control(Flow::Continue)),
+ );
+
+ // Visit the value as normal.
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, OwnedStatic(true)).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ // There is another field.
+ Flow::Continue
+ });
+
+ // The other field.
+ scope.expect_next().once().returning(|mut visitor| {
+ let mut walker = MockWalker::<(), ()>::new();
+
+ // Here we do field a.
+ walker.expect_walk().once().returning(|visitor| {
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, TempBorrowedStatic("a")).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ Ok(())
+ });
+
+ // Tag the value with a key.
+ assert_eq!(
+ visit_tag::<tags::Key, Blocking, _>(TagConst, visitor.cast(), walker).value(),
+ Ok(VisitResult::Control(Flow::Continue)),
+ );
+
+ // The field value.
+ assert_eq!(
+ visit_value::<_, Blocking>(visitor, OwnedStatic(false)).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ // The sequence protocol allows for us to wait to decide if there is another item.
+ Flow::Continue
+ });
+
+ // There are no more fields.
+ scope.expect_next().once().returning(|_visitor| Flow::Done);
+
+ let mut builder = StructBuilder::<Info, DefaultMode, Blocking>::from_seed(()).value();
+ let mut visitor = builder.as_visitor();
+
+ // We need to provide the map tag to the struct before getting into the sequence.
+ // This tag notifies the struct builder to expect the sequence as a map.
+ assert_eq!(
+ visit_tag::<tags::Map, Blocking, _>(TagConst, visitor.cast(), NoopWalker::new()).value(),
+ Ok(VisitResult::Control(Flow::Continue))
+ );
+
+ // Visit the sequence of fields.
+ assert_eq!(
+ visit_sequence(visitor, &mut scope).value(),
+ VisitResult::Control(Flow::Done)
+ );
+
+ // The struct is built as the mock walker above makes it.
+ assert_eq!(builder.build().value().unwrap(), X { a: false, b: true });
+}
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index bad703e..544e54d 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -9,6 +9,8 @@ use std::{
sync::{Mutex, MutexGuard, OnceLock, RwLock},
};
+use treaty::effect::{BlockOn, Spin};
+
pub mod builder;
pub mod protocol;
pub mod walker;
diff --git a/tests/common/protocol/sequence.rs b/tests/common/protocol/sequence.rs
index ff4249f..f4f0abf 100644
--- a/tests/common/protocol/sequence.rs
+++ b/tests/common/protocol/sequence.rs
@@ -41,13 +41,13 @@ impl<'ctx, E: Effect> Sequence<'ctx, E> for MockSequenceVisitor<E> {
}
mock! {
- pub SequenceScopeVisitor<E> {
+ pub SequenceScope<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> {
+impl<'ctx, E: Effect> SequenceScope<'ctx, E> for MockSequenceScope<E> {
fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E> {
E::ready(self.size_hint())
}
diff --git a/tests/protocol_visitor_recoverable.rs b/tests/protocol_visitor_recoverable.rs
index 07ec092..6b70906 100644
--- a/tests/protocol_visitor_recoverable.rs
+++ b/tests/protocol_visitor_recoverable.rs
@@ -1,7 +1,7 @@
use common::protocol::recoverable::MockRecoverableVisitor;
use treaty::{
any::OwnedStatic,
- effect::Blocking,
+ effect::{Blocking, ReadyValue},
protocol::{
visitor::{Recoverable, ValueProto, VisitResult},
DynVisitor,
@@ -30,16 +30,10 @@ fn recoverable_can_be_visited() {
visitor.expect_traits().times(2).return_const(None);
// Attempt to walk once.
- assert_eq!(
- scope.new_walk(DynVisitor(&mut visitor)).into_inner(),
- Ok(())
- );
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Ok(()));
// Attempt to walk twice.
- assert_eq!(
- scope.new_walk(DynVisitor(&mut visitor)).into_inner(),
- Ok(())
- );
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Ok(()));
// We are done.
VisitResult::Control(Flow::Done)
@@ -62,7 +56,7 @@ fn recoverable_can_be_visited() {
// Visit using the recoverable protocol.
assert!(matches!(
- visitor.visit(&mut scope).into_inner(),
+ visitor.visit(&mut scope).value(),
VisitResult::Control(Flow::Done)
));
}
diff --git a/tests/protocol_visitor_request_hint.rs b/tests/protocol_visitor_request_hint.rs
index 06f811f..6c6c2fb 100644
--- a/tests/protocol_visitor_request_hint.rs
+++ b/tests/protocol_visitor_request_hint.rs
@@ -10,7 +10,7 @@ use common::{
use mockall::predicate::eq;
use treaty::{
any::{OwnedStatic, TypeNameId},
- effect::Blocking,
+ effect::{Blocking, ReadyValue},
protocol::{
visitor::{RequestHint, RequestHintProto, ValueKnown, ValueProto, VisitResult},
walker::hint::HintProto,
@@ -37,7 +37,7 @@ fn hints_can_be_requested() {
// Get the known for the value protocol.
assert_eq!(
- obj.known(&()).into_inner(),
+ obj.known(&()).value(),
Ok(ValueKnown {
preview: Some(&OwnedStatic(42))
})
@@ -76,7 +76,7 @@ fn hints_can_be_requested() {
// Request a hint from the visitor.
assert!(matches!(
- visitor.request_hint(DynWalker(&mut mock)).into_inner(),
+ visitor.request_hint(DynWalker(&mut mock)).value(),
VisitResult::Control(Flow::Done)
));
}
diff --git a/tests/protocol_visitor_sequence.rs b/tests/protocol_visitor_sequence.rs
index 1b74c3f..8657daf 100644
--- a/tests/protocol_visitor_sequence.rs
+++ b/tests/protocol_visitor_sequence.rs
@@ -1,11 +1,9 @@
use std::any::TypeId;
-use common::protocol::sequence::{
- MockSequenceScopeVisitor, MockSequenceVisitor, SequenceScopeFactory,
-};
+use common::protocol::sequence::{MockSequenceScope, MockSequenceVisitor, SequenceScopeFactory};
use treaty::{
any::{OwnedStatic, TypeNameId},
- effect::Blocking,
+ effect::{Blocking, ReadyValue},
protocol::{
visitor::{Sequence, SequenceProto, ValueProto, VisitResult},
DynVisitor,
@@ -25,7 +23,7 @@ fn sequence_has_scope_with_size_hint_and_next() {
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)));
+ assert_eq!(scope.size_hint().value(), (1, Some(1)));
let mut visitor = MockBuilder::<(), (), ()>::new();
@@ -33,7 +31,7 @@ fn sequence_has_scope_with_size_hint_and_next() {
visitor.expect_traits().once().return_const(None);
// Get the next item in the sequence from the walker.
- scope.next(DynVisitor(&mut visitor));
+ assert_eq!(scope.next(DynVisitor(&mut visitor)).value(), Flow::Done);
// We are done.
VisitResult::Control(Flow::Done)
@@ -43,7 +41,7 @@ fn sequence_has_scope_with_size_hint_and_next() {
// Everything goes throw the sequence protocol trait.
let visitor: &mut dyn Sequence<Blocking> = &mut mock;
- let mut scope = MockSequenceScopeVisitor::<Blocking>::new();
+ let mut scope = MockSequenceScope::<Blocking>::new();
// Expect a size hint to be asked for.
scope.expect_size_hint().once().return_const((1, Some(1)));
@@ -61,7 +59,7 @@ fn sequence_has_scope_with_size_hint_and_next() {
// Visit a sequence.
assert!(matches!(
- visitor.visit(&mut scope).into_inner(),
+ visitor.visit(&mut scope).value(),
VisitResult::Control(Flow::Done)
));
}
diff --git a/tests/protocol_visitor_tag.rs b/tests/protocol_visitor_tag.rs
index eb24523..cf052c4 100644
--- a/tests/protocol_visitor_tag.rs
+++ b/tests/protocol_visitor_tag.rs
@@ -3,7 +3,7 @@ use std::any::TypeId;
use common::protocol::tag::MockTagVisitor;
use treaty::{
any::{OwnedStatic, TypeNameId},
- effect::Blocking,
+ effect::{Blocking, ReadyValue},
protocol::{
visitor::{Tag, TagConst, TagDyn, TagProto, ValueProto, VisitResult},
DynVisitor,
@@ -34,7 +34,7 @@ fn tag_can_be_visited() {
builder.expect_traits().once().return_const(None);
// Walk the value of the tag.
- walker.walk(DynVisitor(&mut builder));
+ assert_eq!(walker.walk(DynVisitor(&mut builder)).value(), Flow::Done);
// We are done.
VisitResult::Control(Flow::Done)
@@ -62,7 +62,7 @@ fn tag_can_be_visited() {
assert!(matches!(
visitor
.visit(TagDyn(Symbol::new("test")), &mut walker)
- .into_inner(),
+ .value(),
VisitResult::Control(Flow::Done)
));
}
@@ -82,7 +82,7 @@ fn const_tag_can_be_visited() {
builder.expect_traits().once().return_const(None);
// Walk the value of the tag.
- walker.walk(DynVisitor(&mut builder));
+ assert_eq!(walker.walk(DynVisitor(&mut builder)).value(), Flow::Done);
// We are done.
VisitResult::Control(Flow::Done)
@@ -108,7 +108,7 @@ fn const_tag_can_be_visited() {
// Visit the tag protocol for kind test with the value walker.
assert!(matches!(
- visitor.visit(TagConst, &mut walker).into_inner(),
+ visitor.visit(TagConst, &mut walker).value(),
VisitResult::Control(Flow::Done)
));
}
diff --git a/tests/protocol_visitor_value.rs b/tests/protocol_visitor_value.rs
index 374ed99..584e87f 100644
--- a/tests/protocol_visitor_value.rs
+++ b/tests/protocol_visitor_value.rs
@@ -10,7 +10,7 @@ use treaty::{
AnyTrait, BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic,
TempBorrowedMutStaticHrt, TypeNameId,
},
- effect::Blocking,
+ effect::{Blocking, ReadyValue},
protocol::{
visitor::{visit_value, Value, ValueKnown, ValueProto, VisitResult},
walker::hint::Hint,
@@ -43,14 +43,14 @@ fn custom_value_type() {
let visitor: &mut dyn Value<OwnedStatic<MyValue>, Blocking> = &mut mock;
// Visit the value.
- let result = visitor.visit(OwnedStatic(MyValue)).into_inner();
+ let result = visitor.visit(OwnedStatic(MyValue)).value();
// 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(),
+ visit_value::<_, Blocking>(DynVisitor(visitor), OwnedStatic(MyValue)).value(),
VisitResult::Control(Flow::Done)
);
}
@@ -82,11 +82,11 @@ fn borrowed_value() {
let visitor: &mut dyn Value<BorrowedStaticHrt<String>, Blocking> = &mut mock;
// Visit the borrowed value.
- visitor.visit(BorrowedStatic(value));
+ assert_eq!(visitor.visit(BorrowedStatic(value)).value(), Flow::Done.into());
let visitor: &mut (dyn AnyTrait + Send + Sync) = &mut mock;
assert_eq!(
- visit_value::<_, Blocking>(DynVisitor(visitor), BorrowedStatic(value)).into_inner(),
+ visit_value::<_, Blocking>(DynVisitor(visitor), BorrowedStatic(value)).value(),
VisitResult::Control(Flow::Done)
);
}
@@ -126,7 +126,7 @@ fn temp_borrowed_value() {
// Visit the context to show we can shorten the lifetime.
// This would also force the lifetime to be to long if this wasn't the Temp form.
- visitor.visit(TempBorrowedMutStatic(value));
+ assert_eq!(visitor.visit(TempBorrowedMutStatic(value)).value(), Flow::Done.into());
// Temporary scope (smaller than the context we set above).
{
@@ -134,7 +134,7 @@ fn temp_borrowed_value() {
let mut value = String::from("test");
// Visit the temp value.
- visitor.visit(TempBorrowedMutStatic(&mut value));
+ assert_eq!(visitor.visit(TempBorrowedMutStatic(&mut value)).value(), Flow::Done.into());
}
// Force the visitor to outlive the temporary scope.
@@ -174,19 +174,19 @@ fn all_visit_results() {
// Visit can return a done.
assert_eq!(
- visitor.visit(OwnedStatic(0)).into_inner(),
+ visitor.visit(OwnedStatic(0)).value(),
VisitResult::Control(Flow::Done)
);
// Visit can return an error signal.
assert_eq!(
- visitor.visit(OwnedStatic(1)).into_inner(),
+ visitor.visit(OwnedStatic(1)).value(),
VisitResult::Control(Flow::Err)
);
// Visit can return a continue.
assert_eq!(
- visitor.visit(OwnedStatic(2)).into_inner(),
+ visitor.visit(OwnedStatic(2)).value(),
VisitResult::Control(Flow::Continue)
);
@@ -194,7 +194,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_inner(),
+ visitor.visit(OwnedStatic(3)).value(),
VisitResult::Skipped(OwnedStatic(3))
);
}
@@ -232,7 +232,7 @@ fn as_hint() {
// The value protocol has no hint data, and it has no known data.
assert_eq!(
- walker.known(&()).into_inner(),
+ walker.known(&()).value(),
Ok(ValueKnown {
preview: Some(&OwnedStatic(42))
})
@@ -254,7 +254,7 @@ fn as_hint() {
// The value protocol has no hint data, and it has no known data.
assert_eq!(
- walker.known(&()).into_inner(),
+ walker.known(&()).value(),
Ok(ValueKnown {
preview: Some(&BorrowedStatic(&42))
})
@@ -272,9 +272,6 @@ fn as_hint() {
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_inner(),
- Ok(ValueKnown { preview: None })
- );
+ assert_eq!(walker.known(&()).value(), Ok(ValueKnown { preview: None }));
}
}
diff --git a/tests/protocol_walker_hint.rs b/tests/protocol_walker_hint.rs
index d15d345..4cb41dd 100644
--- a/tests/protocol_walker_hint.rs
+++ b/tests/protocol_walker_hint.rs
@@ -3,7 +3,7 @@ use std::any::TypeId;
use common::protocol::hint::MockHintWalker;
use treaty::{
any::TypeNameId,
- effect::{Blocking, Effect, Future, Spin},
+ effect::{Blocking, Effect, Future, ReadyValue, Spin},
hkt::higher_ranked_type,
protocol::{
walker::hint::{self, Hint, HintMeta, HintProto, Meta, MetaKnown},
@@ -66,14 +66,14 @@ fn can_get_known_and_hint() {
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)));
+ assert_eq!(walker.known(&Hint(42)).value(), 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));
+ assert_eq!(walker.hint(DynVisitor(&mut mock), Hint(123)).value(), Flow::Done);
}
}
@@ -130,7 +130,7 @@ fn known_can_have_temp_mutable_borrow() {
// 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)));
+ assert_eq!(walker.known(&()).value(), Ok(Known(&mut x)));
}
drop(context);
@@ -177,16 +177,16 @@ fn known_can_have_context_borrow() {
}
}
- let mut context = String::from("test");
+ let context = String::from("test");
let ctx = {
- let mut walker = Walker(&mut context);
+ let mut walker = Walker(&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 {
+ let Ok(Known(y)) = walker.known(&()).value() else {
unreachable!()
};
y
@@ -239,7 +239,7 @@ fn hint_can_have_temp_mutable_borrow() {
assert_eq!(
walker
.hint(DynVisitor(&mut visitor), Hint(&mut temp))
- .into_inner(),
+ .value(),
Flow::Done
);
@@ -289,7 +289,7 @@ fn hint_can_have_context_borrow() {
assert_eq!(
walker
.hint(DynVisitor(&mut visitor), Hint(&context))
- .into_inner(),
+ .value(),
Flow::Done
);
}
diff --git a/tests/walker_struct.rs b/tests/walker_struct.rs
index b467a4c..26f8935 100644
--- a/tests/walker_struct.rs
+++ b/tests/walker_struct.rs
@@ -1,12 +1,12 @@
use mockall::predicate::eq;
use treaty::{
any::{BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TypeNameId},
- effect::{Blocking, Effect, Future},
+ effect::{Blocking, Effect, Future, ReadyValue},
protocol::{
visitor::{tags, SequenceProto, TagConst, TagProto, ValueProto, VisitResult},
DynVisitor,
},
- walkers::core::r#struct::{StructTypeInfo, StructWalker},
+ walkers::core::r#struct::{StaticType, StructTypeInfo, StructWalker},
Builder, DefaultMode, Flow, Walker,
};
@@ -36,6 +36,8 @@ impl<'ctx, M> StructTypeInfo<'ctx, M> for Info {
type FieldError = ();
+ type S = StaticType;
+
type T = X;
fn walk_field<'a, E: Effect>(
@@ -53,7 +55,7 @@ impl<'ctx, M> StructTypeInfo<'ctx, M> for Info {
.unwrap();
// Emit the field value.
- obj.visit(OwnedStatic(value.a)).await;
+ assert_eq!(obj.visit(OwnedStatic(value.a)).await, Flow::Done.into());
// There are more fields.
Ok(Flow::Continue)
@@ -65,7 +67,7 @@ impl<'ctx, M> StructTypeInfo<'ctx, M> for Info {
.unwrap();
// Emit the field value.
- obj.visit(OwnedStatic(value.b)).await;
+ assert_eq!(obj.visit(OwnedStatic(value.b)).await, Flow::Done.into());
// There are no more fields.
Ok(Flow::Done)
@@ -86,7 +88,7 @@ fn sequence_of_field_values() {
let value = X { a: true, b: 42 };
// The struct walker using the info we provided about the struct.
- let walker = StructWalker::<X, Info, DefaultMode, Blocking>::new(&value);
+ let walker = StructWalker::<Info, _, DefaultMode, Blocking>::new(&value);
let mut builder = MockBuilder::<(), (), ()>::new();
@@ -102,7 +104,7 @@ fn sequence_of_field_values() {
visitor.expect_visit().once().return_const(
(|_, scope| {
// The struct should have exactly 2 fields.
- assert_eq!(scope.size_hint().into_inner(), (2, Some(2)));
+ assert_eq!(scope.size_hint().value(), (2, Some(2)));
// Get the first field value.
{
@@ -129,7 +131,7 @@ fn sequence_of_field_values() {
Some(Box::new(visitor))
});
- scope.next(Builder::<Blocking>::as_visitor(&mut visitor));
+ assert_eq!(scope.next(Builder::<Blocking>::as_visitor(&mut visitor)).value(), Flow::Continue);
}
// Get the second field value.
@@ -157,7 +159,7 @@ fn sequence_of_field_values() {
Some(Box::new(visitor))
});
- scope.next(Builder::<Blocking>::as_visitor(&mut visitor));
+ assert_eq!(scope.next(Builder::<Blocking>::as_visitor(&mut visitor)).value(), Flow::Done);
}
// We are done with the sequence of fields.
@@ -175,7 +177,7 @@ fn sequence_of_field_values() {
assert_eq!(
walker
.walk(Builder::<Blocking>::as_visitor(&mut builder))
- .into_inner(),
+ .value(),
Ok(())
);
}
@@ -186,7 +188,7 @@ fn has_struct_tag() {
let value = X { a: true, b: 42 };
// The struct walker using the info we provided about the struct.
- let walker = StructWalker::<X, Info, DefaultMode, Blocking>::new(&value);
+ let walker = StructWalker::<Info, _, DefaultMode, Blocking>::new(&value);
let mut builder = MockBuilder::<(), (), ()>::new();
@@ -212,10 +214,7 @@ fn has_struct_tag() {
let mut visitor = MockBuilder::<(), (), ()>::new();
// Walk the noop walker so there isn't an error.
- assert_eq!(
- walker.walk(DynVisitor(&mut visitor)).into_inner(),
- Flow::Done
- );
+ assert_eq!(walker.walk(DynVisitor(&mut visitor)).value(), Flow::Done);
// We are done, the walker should now stop early.
VisitResult::Control(Flow::Done)
@@ -228,7 +227,7 @@ fn has_struct_tag() {
assert_eq!(
walker
.walk(Builder::<Blocking>::as_visitor(&mut builder))
- .into_inner(),
+ .value(),
Ok(())
);
}
@@ -239,7 +238,7 @@ fn has_map_backup_tag() {
let value = X { a: true, b: 42 };
// The struct walker using the info we provided about the struct.
- let walker = StructWalker::<X, Info, DefaultMode, Blocking>::new(&value);
+ let walker = StructWalker::<Info, _, DefaultMode, Blocking>::new(&value);
let mut builder = MockBuilder::<(), (), ()>::new();
@@ -267,10 +266,7 @@ fn has_map_backup_tag() {
let mut visitor = MockBuilder::<(), (), ()>::new();
// Walk the noop walker so there isn't an error.
- assert_eq!(
- walker.walk(DynVisitor(&mut visitor)).into_inner(),
- Flow::Done
- );
+ assert_eq!(walker.walk(DynVisitor(&mut visitor)).value(), Flow::Done);
// We are done, the walker should now stop early.
VisitResult::Control(Flow::Done)
@@ -283,7 +279,7 @@ fn has_map_backup_tag() {
assert_eq!(
walker
.walk(Builder::<Blocking>::as_visitor(&mut builder))
- .into_inner(),
+ .value(),
Ok(())
);
}
@@ -294,7 +290,7 @@ fn borrowed_value_directly() {
let value = X { a: true, b: 42 };
// The struct walker using the info we provided about the struct.
- let walker = StructWalker::<X, Info, DefaultMode, Blocking>::new(&value);
+ let walker = StructWalker::<Info, _, DefaultMode, Blocking>::new(&value);
let mut builder = MockBuilder::<(), (), ()>::new();
@@ -338,7 +334,7 @@ fn borrowed_value_directly() {
assert_eq!(
walker
.walk(Builder::<Blocking>::as_visitor(&mut builder))
- .into_inner(),
+ .value(),
Ok(())
);
}