added tests for tuple and map like structs
| -rw-r--r-- | src/any.rs | 22 | ||||
| -rw-r--r-- | src/build/builders/core.rs | 17 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 2 | ||||
| -rw-r--r-- | src/build/builders/core/struct.rs | 285 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 8 | ||||
| -rw-r--r-- | src/effect.rs | 68 | ||||
| -rw-r--r-- | src/lib.rs | 16 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 22 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 2 | ||||
| -rw-r--r-- | src/transform.rs | 1 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 115 | ||||
| -rw-r--r-- | tests/builder_struct.rs | 285 | ||||
| -rw-r--r-- | tests/common/mod.rs | 2 | ||||
| -rw-r--r-- | tests/common/protocol/sequence.rs | 4 | ||||
| -rw-r--r-- | tests/protocol_visitor_recoverable.rs | 14 | ||||
| -rw-r--r-- | tests/protocol_visitor_request_hint.rs | 6 | ||||
| -rw-r--r-- | tests/protocol_visitor_sequence.rs | 14 | ||||
| -rw-r--r-- | tests/protocol_visitor_tag.rs | 10 | ||||
| -rw-r--r-- | tests/protocol_visitor_value.rs | 31 | ||||
| -rw-r--r-- | tests/protocol_walker_hint.rs | 18 | ||||
| -rw-r--r-- | tests/walker_struct.rs | 42 |
21 files changed, 809 insertions, 175 deletions
@@ -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)) } } @@ -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(()) ); } |