added value builder
| -rw-r--r-- | src/any.rs | 9 | ||||
| -rw-r--r-- | src/build.rs | 2 | ||||
| -rw-r--r-- | src/build/builders/core.rs | 1 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 100 | ||||
| -rw-r--r-- | src/build/builders/core/struct.rs | 86 | ||||
| -rw-r--r-- | src/build/builders/core/value.rs | 231 | ||||
| -rw-r--r-- | src/effect/async.rs | 2 | ||||
| -rw-r--r-- | src/effect/blocking.rs | 1 | ||||
| -rw-r--r-- | src/lib.rs | 34 | ||||
| -rw-r--r-- | src/macros/build.rs | 33 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 10 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 2 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 3 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 15 | ||||
| -rw-r--r-- | src/transform.rs | 43 | ||||
| -rw-r--r-- | src/walk.rs | 4 | ||||
| -rw-r--r-- | src/walk/walkers/core/bool.rs | 13 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 125 | ||||
| -rw-r--r-- | tests/builder_value.rs | 38 | ||||
| -rw-r--r-- | tests/common/builder.rs | 2 | ||||
| -rw-r--r-- | tests/common/protocol/hint.rs | 4 | ||||
| -rw-r--r-- | tests/common/walker.rs | 3 | ||||
| -rw-r--r-- | tests/protocol_walker_hint.rs | 10 |
23 files changed, 530 insertions, 241 deletions
@@ -155,6 +155,11 @@ where // } // ``` pub trait AnyTrait<'ctx> { + /// The trait objects this type can be upcasted to. + type Available + where + Self: Sized; + /// Upcast a borrow to the given trait object. /// /// Use the `<dyn AnyTrait>::upcast()` helper method instead, if possible. @@ -252,6 +257,10 @@ macro_rules! any_trait { impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name $(where $($bound)*)? { + type Available = ( + $($protocol,)* + ); + #[inline(always)] fn upcast_to_id<'__>( &'__ self, diff --git a/src/build.rs b/src/build.rs index 51404a4..372eac8 100644 --- a/src/build.rs +++ b/src/build.rs @@ -7,7 +7,7 @@ use crate::{ }; /// A buildable type. -pub trait Build<'ctx, M: 'ctx, E: Effect>: Sized + Send + Sync { +pub trait Build<'ctx, M, E: Effect>: Sized + Send + Sync { /// The builder that can be used to build a value of `Self`. type Builder: Builder<'ctx, E, Value = Self>; } diff --git a/src/build/builders/core.rs b/src/build/builders/core.rs index 627f84a..db7bc5d 100644 --- a/src/build/builders/core.rs +++ b/src/build/builders/core.rs @@ -7,6 +7,7 @@ use crate::{ // pub mod array; pub mod bool; +pub mod value; // pub mod option; // pub mod variant; diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs index aa72f20..f6c33b2 100644 --- a/src/build/builders/core/bool.rs +++ b/src/build/builders/core/bool.rs @@ -1,90 +1,18 @@ -use core::{fmt::Display, marker::PhantomData}; +use crate::effect::Effect; -use crate::{ - any::OwnedStatic, - any_trait, - effect::{Effect, ErasedEffective}, - protocol::{ - visitor::{Value, ValueProto, VisitResult}, - DynVisitor, - }, - Flow, -}; +use super::value::{Cloneable, ValueBuilder}; -impl<'ctx, M: 'ctx, E: Effect> crate::Build<'ctx, M, E> for bool { - type Builder = Builder<E>; +macro_rules! value_builder { + [$($ty:ty),*] => { + $(impl<'ctx, M, E: Effect> crate::Build<'ctx, M, E> for $ty { + type Builder = ValueBuilder<$ty, Cloneable, E>; + })* + }; } -#[derive(Debug)] -pub enum Error { - Incomplete, -} - -impl Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Error::Incomplete => write!(f, "Incomplete"), - } - } -} - -pub struct Builder<E>(Option<bool>, PhantomData<fn() -> E>); - -impl crate::BuilderTypes for bool { - type Seed = (); - - type Error = Error; - - type Value = bool; -} - -impl<E> crate::BuilderTypes for Builder<E> { - type Error = Error; - - type Value = bool; - - type Seed = (); -} - -impl<'ctx, E: Effect> crate::Builder<'ctx, E> for Builder<E> { - #[inline(always)] - fn build<'a>(self) -> ErasedEffective<'a, Result<Self::Value, Self::Error>, E> - where - Self: 'a, - { - E::ready(self.0.ok_or(Error::Incomplete)) - } - - #[inline(always)] - fn from_seed<'a>(_seed: Self::Seed) -> ErasedEffective<'a, Self, E> - where - Self: 'a, - { - E::ready(Self(None, PhantomData)) - } - - #[inline(always)] - fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> { - DynVisitor(self) - } -} - -any_trait! { - impl['ctx, E] Builder<E> = [ - ValueProto<OwnedStatic<bool>, E>, - ] where E: Effect -} - -impl<'ctx, E: Effect> Value<'ctx, OwnedStatic<bool>, E> for Builder<E> { - #[inline(always)] - fn visit<'a>( - &'a mut self, - OwnedStatic(value): OwnedStatic<bool>, - ) -> ErasedEffective<'a, VisitResult<OwnedStatic<bool>>, E> - where - 'ctx: 'a, - { - self.0 = Some(value); - E::ready(Flow::Done.into()) - } -} +value_builder![u8, u16, u32, u64, u128, usize]; +value_builder![i8, i16, i32, i64, i128, isize]; +value_builder![f32, f64]; +value_builder![char]; +value_builder![bool]; +value_builder![()]; diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs index e011eff..9ee98aa 100644 --- a/src/build/builders/core/struct.rs +++ b/src/build/builders/core/struct.rs @@ -24,20 +24,20 @@ use super::NoopVisitor; /// A builder for a struct. pub struct StructBuilder<'ctx, Info, Mode, E: Effect> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { inner: Inner<'ctx, Info, Mode, E>, } enum Inner<'ctx, Info, Mode, E: Effect> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { Temp, Seed(Info::Seed), Builders { /// The builders for all the struct's fields. - builders: Info::Builders<E>, + builders: Info::Builders, /// The kind of struct the builder is expecting. kind: StructKind, @@ -61,9 +61,9 @@ enum StructKind { /// /// The `Mode` generic allows implementations to change depending on the mode the user gives. /// It is not used by the trait directly. -pub trait StructTypeInfo<'ctx, Mode>: 'static { +pub trait StructTypeInfo<'ctx, Mode: 'ctx, E: Effect>: 'static { /// A struct of builders for each field. - type Builders<E: Effect>: Ss; + type Builders: Ss; /// The seed value needed to make the builders. type Seed: Ss; @@ -85,19 +85,19 @@ pub trait StructTypeInfo<'ctx, Mode>: 'static { const FIELD_COUNT: usize; /// Create a set of builders from a seed value. - fn new_builders<'a, E: Effect>(seed: Self::Seed) -> ErasedEffective<'a, Self::Builders<E>, E>; + fn new_builders<'a>(seed: Self::Seed) -> ErasedEffective<'a, Self::Builders, E>; /// Finish building the struct value. - fn from_builders<'a, E: Effect>( - builders: Self::Builders<E>, + fn from_builders<'a>( + builders: Self::Builders, ) -> ErasedEffective<'a, Result<Self::T, Self::Error>, E>; /// Get the visitor for a field. /// /// This is how [`StructBuilder`] picks a field builder to use. - fn as_visitor<'a, E: Effect>( + fn as_visitor<'a>( marker: Self::FieldMarker, - builders: &'a mut Self::Builders<E>, + builders: &'a mut Self::Builders, ) -> DynVisitor<'a, 'ctx>; /// Get a field marker from the index of the field. @@ -113,35 +113,35 @@ pub trait StructTypeInfo<'ctx, Mode>: 'static { } /// Error that [`StructBuilder`] returns. -pub struct StructError<'ctx, Info, M> +pub struct StructError<'ctx, Info, M, E: Effect> where - Info: StructTypeInfo<'ctx, M>, + Info: StructTypeInfo<'ctx, M, E>, { /// Error from the struct info definition. error: Info::Error, } -impl<'ctx, Info, Mode> StructError<'ctx, Info, Mode> +impl<'ctx, Info, Mode, E: Effect> StructError<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { fn from_field_err(error: Info::Error) -> Self { Self { error } } } -impl<'ctx, Info, Mode> Debug for StructError<'ctx, Info, Mode> +impl<'ctx, Info, Mode, E: Effect> Debug for StructError<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("StructError").field(&self.error).finish() } } -impl<'ctx, Info, Mode> Display for StructError<'ctx, Info, Mode> +impl<'ctx, Info, Mode, E: Effect> Display for StructError<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { Display::fmt(&self.error, f) @@ -150,25 +150,25 @@ where impl<'ctx, Info, Mode, E: Effect> BuilderTypes for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { type Seed = Info::Seed; - type Error = StructError<'ctx, Info, Mode>; + type Error = StructError<'ctx, Info, Mode, E>; type Value = Info::T; } impl<'ctx, Info, Mode: 'ctx, E: Effect> StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { fn make_builders<'e>(&'e mut self) -> ErasedEffective<'e, (), E> where 'ctx: 'e, { match core::mem::replace(&mut self.inner, Inner::Temp) { - Inner::Seed(seed) => Info::new_builders::<E>(seed).map(|builders| { + Inner::Seed(seed) => Info::new_builders(seed).map(|builders| { self.inner = Inner::Builders { builders, kind: StructKind::Tuple, @@ -185,7 +185,7 @@ where impl<'ctx, Info, Mode: 'ctx, E: Effect> Builder<'ctx, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, { fn from_seed<'a>(seed: Self::Seed) -> ErasedEffective<'a, Self, E> where @@ -205,7 +205,7 @@ where Inner::Temp => unreachable!(), Inner::Seed(seed) => { // We may be able to make a value from just the seed. - Info::new_builders::<E>(seed) + Info::new_builders(seed) .then(|builders| Info::from_builders(builders)) .map(|result| result.map_err(StructError::from_field_err)) } @@ -233,13 +233,13 @@ any_trait! { SequenceProto<E> ] where E: Effect, - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, Mode: 'ctx, } impl<'ctx, Info, Mode: 'ctx, E> RequestHint<'ctx, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, E: Effect, { #[inline(always)] @@ -250,12 +250,12 @@ where E::as_ctx((self, walker), |(this, walker)| { // Start with a hint to use the value protocol to directly transfer the // struct value. - hint_protocol::<ValueProto<Info::ValueT, E>, _>(walker.cast(), *this, ()).cast() + hint_protocol::<ValueProto<Info::ValueT, E>>(walker.cast(), *this, ()).cast() }) .if_not_finished(|(this, walker)| { // Next hint that the struct protocol should be used to switch into // map-like if the walker supports it. - hint_protocol::<TagProto<tags::Struct, E>, _>( + hint_protocol::<TagProto<tags::Struct, E>>( walker.cast(), *this, TagHint { kind: TagConst }, @@ -266,7 +266,7 @@ where // If the struct hint didn't work, // then hint that the map protocol should be used to switch into // map-like if the walker supports it. - hint_protocol::<TagProto<tags::Map, E>, _>( + hint_protocol::<TagProto<tags::Map, E>>( walker.cast(), *this, TagHint { kind: TagConst }, @@ -276,7 +276,7 @@ where .if_not_finished(|(this, walker)| { // Lastly hint to use a sequence to get the field values. // We hint with the exact number of fields we are expecting. - hint_protocol::<SequenceProto<E>, _>( + hint_protocol::<SequenceProto<E>>( walker.cast(), *this, SequenceHint { @@ -297,7 +297,7 @@ where /// This skips needing to go through each field individually. impl<'ctx, Info, Mode, E> Value<'ctx, Info::ValueT, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, E: Effect, { fn visit<'a>( @@ -321,7 +321,7 @@ where /// By default [`StructBuilder`] expects a tuple-like struct. impl<'ctx, Info, Mode: 'ctx, E> Tag<'ctx, tags::Struct, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, E: Effect, { fn visit<'this: 'e, 'walker: 'e, 'e>( @@ -347,7 +347,7 @@ where /// By default [`StructBuilder`] expects a tuple-like struct. impl<'ctx, Info, Mode: 'ctx, E> Tag<'ctx, tags::Map, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, E: Effect, { fn visit<'this: 'e, 'walker: 'e, 'e>( @@ -376,7 +376,7 @@ where /// a sequence of key value pairs. Where the key is the field name. impl<'ctx, Info, Mode: 'ctx, E> Sequence<'ctx, E> for StructBuilder<'ctx, Info, Mode, E> where - Info: StructTypeInfo<'ctx, Mode>, + Info: StructTypeInfo<'ctx, Mode, E>, E: Effect, { fn visit<'a: 'c, 'b: 'c, 'c>( @@ -448,8 +448,8 @@ where } } -struct FieldVisitor<'a, 'ctx, I: StructTypeInfo<'ctx, M>, M, E: Effect> { - builders: &'a mut I::Builders<E>, +struct FieldVisitor<'a, 'ctx, I: StructTypeInfo<'ctx, M, E>, M, E: Effect> { + builders: &'a mut I::Builders, marker: Option<I::FieldMarker>, _marker: Marker<E>, } @@ -468,13 +468,13 @@ any_trait! { }) } where E: Effect, - I: StructTypeInfo<'ctx, M>, + I: StructTypeInfo<'ctx, M, E>, } impl<'d, 'ctx, I, M, E> Tag<'ctx, tags::Key, E> for FieldVisitor<'d, 'ctx, I, M, E> where E: Effect, - I: StructTypeInfo<'ctx, M>, + I: StructTypeInfo<'ctx, M, E>, { fn visit<'a: 'c, 'b: 'c, 'c>( &'a mut self, @@ -495,7 +495,7 @@ where } } -struct NameVisitor<'ctx, I: StructTypeInfo<'ctx, M>, M, E: Effect> { +struct NameVisitor<'ctx, I: StructTypeInfo<'ctx, M, E>, M, E: Effect> { field_marker: Option<I::FieldMarker>, _marker: Marker<E>, } @@ -507,13 +507,13 @@ any_trait! { ValueProto<OwnedStatic<&'static str>, E>, ] where E: Effect, - I: StructTypeInfo<'ctx, M>, + 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>, + I: StructTypeInfo<'ctx, M, E>, { fn visit<'a>( &'a mut self, @@ -532,7 +532,7 @@ where impl<'ctx, I, M, E> Value<'ctx, TempBorrowedStaticHrt<str>, E> for NameVisitor<'ctx, I, M, E> where E: Effect, - I: StructTypeInfo<'ctx, M>, + I: StructTypeInfo<'ctx, M, E>, { fn visit<'a>( &'a mut self, @@ -551,7 +551,7 @@ where impl<'ctx, I, M, E> Value<'ctx, OwnedStatic<&'static str>, E> for NameVisitor<'ctx, I, M, E> where E: Effect, - I: StructTypeInfo<'ctx, M>, + I: StructTypeInfo<'ctx, M, E>, { fn visit<'a>( &'a mut self, diff --git a/src/build/builders/core/value.rs b/src/build/builders/core/value.rs new file mode 100644 index 0000000..d82ea1e --- /dev/null +++ b/src/build/builders/core/value.rs @@ -0,0 +1,231 @@ +use core::fmt::Display; + +use crate::{ + any::{ + AnyTrait, BorrowedMutStatic, BorrowedMutStaticHrt, BorrowedStatic, BorrowedStaticHrt, + OwnedStatic, TempBorrowedMutStatic, TempBorrowedMutStaticHrt, TempBorrowedStatic, + TempBorrowedStaticHrt, + }, + any_trait, + effect::{Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss}, + hkt::Marker, + protocol::{ + visitor::{ + EffectiveVisitExt as _, RequestHint, RequestHintProto, Value, ValueProto, VisitResult, + }, + walker::hint::hint_protocol, + DynVisitor, DynWalker, + }, + Flow, +}; + +#[non_exhaustive] +pub struct ValueError<T>(Marker<T>); + +impl<T> ::core::fmt::Debug for ValueError<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "missing value of type `{}`", core::any::type_name::<T>()) + } +} + +impl<T> Display for ValueError<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "missing value of type `{}`", core::any::type_name::<T>()) + } +} + +pub enum Cloneable {} +pub enum NotCloneable {} + +/// Builder for `'static` values. +/// +/// This builder only uses the [`Value`] protocol. +pub struct ValueBuilder<T, Clone, E> { + value: Option<T>, + _marker: Marker<(E, Clone)>, +} + +impl<T: Ss, Clone, E> crate::BuilderTypes for ValueBuilder<T, Clone, E> { + type Error = ValueError<T>; + + type Value = T; + + type Seed = (); +} + +impl<'ctx, T: Ss + 'static, Clone, E: Effect> crate::Builder<'ctx, E> for ValueBuilder<T, Clone, E> +where + Self: AnyTrait<'ctx>, +{ + fn build<'a>(self) -> ErasedEffective<'a, Result<Self::Value, Self::Error>, E> + where + Self: 'a, + { + E::ready(self.value.ok_or(ValueError(Default::default()))) + } + + fn from_seed<'a>(_seed: Self::Seed) -> ErasedEffective<'a, Self, E> + where + Self: 'a, + { + E::ready(Self { + value: None, + _marker: Default::default(), + }) + } + + fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> { + DynVisitor(self) + } +} + +any_trait! { + impl['ctx, T, E] ValueBuilder<T, NotCloneable, E> = [ + RequestHintProto<E>, + ValueProto<OwnedStatic<T>, E>, + ] where + E: Effect, + T: Ss + 'static +} + +any_trait! { + impl['ctx, T, E] ValueBuilder<T, Cloneable, E> = [ + RequestHintProto<E>, + ValueProto<OwnedStatic<T>, E>, + ValueProto<BorrowedStaticHrt<T>, E>, + ValueProto<TempBorrowedStaticHrt<T>, E>, + ValueProto<BorrowedMutStaticHrt<T>, E>, + ValueProto<TempBorrowedMutStaticHrt<T>, E>, + ] where + E: Effect, + T: Ss + 'static + Clone, +} + +impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T, NotCloneable, E> { + fn request_hint<'a>( + &'a mut self, + walker: DynWalker<'a, 'ctx>, + ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { + E::as_ctx((self, walker), |(this, walker)| { + hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast() + }) + .map(|((_, walker), result)| result.map_skipped(|_| walker)) + } +} + +impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T, Cloneable, E> +where + T: Clone, +{ + fn request_hint<'a>( + &'a mut self, + walker: DynWalker<'a, 'ctx>, + ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { + E::as_ctx((self, walker), |(this, walker)| { + hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast() + }) + .if_not_finished(|(this, walker)| { + hint_protocol::<ValueProto<BorrowedStaticHrt<T>, E>>(walker.cast(), *this, ()).cast() + }) + .if_not_finished(|(this, walker)| { + hint_protocol::<ValueProto<TempBorrowedStaticHrt<T>, E>>(walker.cast(), *this, ()) + .cast() + }) + .if_not_finished(|(this, walker)| { + hint_protocol::<ValueProto<BorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ()).cast() + }) + .if_not_finished(|(this, walker)| { + hint_protocol::<ValueProto<TempBorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ()) + .cast() + }) + .map(|((_, walker), result)| result.map_skipped(|_| walker)) + } +} + +impl<'ctx, T: Ss + 'static, Clone, E: Effect> Value<'ctx, OwnedStatic<T>, E> + for ValueBuilder<T, Clone, E> +{ + fn visit<'a>( + &'a mut self, + OwnedStatic(value): OwnedStatic<T>, + ) -> ErasedEffective<'a, VisitResult<OwnedStatic<T>>, E> + where + 'ctx: 'a, + { + self.value = Some(value); + + E::ready(Flow::Done.into()) + } +} + +impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, BorrowedStaticHrt<T>, E> + for ValueBuilder<T, Cloneable, E> +where + T: Clone, +{ + fn visit<'a>( + &'a mut self, + BorrowedStatic(value): BorrowedStatic<'ctx, T>, + ) -> ErasedEffective<'a, VisitResult<BorrowedStatic<'ctx, T>>, E> + where + 'ctx: 'a, + { + self.value = Some(value.clone()); + + E::ready(Flow::Done.into()) + } +} + +impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, TempBorrowedStaticHrt<T>, E> + for ValueBuilder<T, Cloneable, E> +where + T: Clone, +{ + fn visit<'a>( + &'a mut self, + TempBorrowedStatic(value): TempBorrowedStatic<'a, T>, + ) -> ErasedEffective<'a, VisitResult<TempBorrowedStatic<'a, T>>, E> + where + 'ctx: 'a, + { + self.value = Some(value.clone()); + + E::ready(Flow::Done.into()) + } +} + +impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, BorrowedMutStaticHrt<T>, E> + for ValueBuilder<T, Cloneable, E> +where + T: Clone, +{ + fn visit<'a>( + &'a mut self, + BorrowedMutStatic(value): BorrowedMutStatic<'ctx, T>, + ) -> ErasedEffective<'a, VisitResult<BorrowedMutStatic<'ctx, T>>, E> + where + 'ctx: 'a, + { + self.value = Some(value.clone()); + + E::ready(Flow::Done.into()) + } +} + +impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, TempBorrowedMutStaticHrt<T>, E> + for ValueBuilder<T, Cloneable, E> +where + T: Clone, +{ + fn visit<'a>( + &'a mut self, + TempBorrowedMutStatic(value): TempBorrowedMutStatic<'a, T>, + ) -> ErasedEffective<'a, VisitResult<TempBorrowedMutStatic<'a, T>>, E> + where + 'ctx: 'a, + { + self.value = Some(value.clone()); + + E::ready(Flow::Done.into()) + } +} diff --git a/src/effect/async.rs b/src/effect/async.rs index fd0bbf0..1a910d4 100644 --- a/src/effect/async.rs +++ b/src/effect/async.rs @@ -16,6 +16,7 @@ enum ErasedFutureKind<'lt, T> { Ready(T), } +#[must_use] pub struct ErasedFuture<'lt, T> { kind: ErasedFutureKind<'lt, T>, } @@ -26,6 +27,7 @@ enum EffectFutureKind<'lt, T> { Ready(#[pin] ::core::future::Ready<T>), } +#[must_use] #[pin_project] pub struct EffectFuture<'lt, T> { #[pin] diff --git a/src/effect/blocking.rs b/src/effect/blocking.rs index bc9508d..39ea3ac 100644 --- a/src/effect/blocking.rs +++ b/src/effect/blocking.rs @@ -15,6 +15,7 @@ pub trait BlockOn: 'static { pub struct Blocking<B = Spin>(Marker<B>); +#[must_use] #[repr(transparent)] pub struct Value<T, B>(pub T, Marker<B>); @@ -125,8 +125,8 @@ macro_rules! Walk { impl<'ctx, M: 'ctx, E: $crate::effect::Effect> $crate::Walk<'ctx, M, E> for &'ctx $name { type Walker = $crate::walkers::core::r#struct::StructWalker<'ctx, Info, $crate::any::StaticType, M, E>; - fn into_walker(self) -> Self::Walker { - $crate::walkers::core::r#struct::StructWalker::new(self) + fn into_walker<'e>(self) -> $crate::effect::ErasedEffective<'e, Self::Walker, E> { + E::ready($crate::walkers::core::r#struct::StructWalker::new(self)) } } @@ -173,11 +173,13 @@ macro_rules! Walk { $(fields::$field => { let key_walker = $crate::walkers::core::value::ValueWalker::new(stringify!($field)); - let value_walker = <&'ctx $type as $crate::Walk::<'ctx, M, E>>::into_walker(&value.$field); + <&'ctx $type as $crate::Walk::<'ctx, M, E>>::into_walker(&value.$field) + .then(|value_walker| { + let walker = $crate::walkers::core::key_value::KeyValueWalker::<$crate::protocol::visitor::TagConst<{ $crate::TAG_FIELD.to_int() }>, _, _>::new($crate::protocol::visitor::TagConst, key_walker, value_walker); - let walker = $crate::walkers::core::key_value::KeyValueWalker::<$crate::protocol::visitor::TagConst<{ $crate::TAG_FIELD.to_int() }>, _, _>::new($crate::protocol::visitor::TagConst, key_walker, value_walker); - - $crate::Walker::<'ctx, E>::walk(walker, visitor).map(|result| match result { + $crate::Walker::<'ctx, E>::walk(walker, visitor) + }) + .map(|result| match result { Ok(_) => { Ok($crate::Flow::Continue) } @@ -261,12 +263,28 @@ pub mod demo { #[inline(never)] pub fn ident(x: X) -> Y { - // Y::build(x.as_walker()).unwrap() - x.walk(Y::new_builder()).unwrap() + Y::build(x.as_walker()).unwrap() + // x.walk(Y::new_builder()).unwrap() } #[test] fn demo() { + use crate::effect::blocking::BlockOn as _; + assert_eq!(ident(X { a: true, b: false }), Y { a: true, b: false }); + + crate::effect::blocking::Spin::block_on(async { + let x = X { a: false, b: true }; + + let y = Y::build_async(x.as_async_walker().await).await.unwrap(); + + assert_eq!(y, Y { a: false, b: true }); + }); + + let x = X { a: false, b: true }; + + let y = Y::build(x.as_walker()).unwrap(); + + assert_eq!(y, Y { a: false, b: true }); } } diff --git a/src/macros/build.rs b/src/macros/build.rs index 9511465..9e7ced9 100644 --- a/src/macros/build.rs +++ b/src/macros/build.rs @@ -12,7 +12,7 @@ macro_rules! Build { type Builder = $crate::builders::core::r#struct::StructBuilder<'ctx, __Info, M, E>; } - $vis struct Builders<'ctx, M, E: $crate::effect::Effect> { + $vis struct Builders<'ctx, M: 'ctx, E: $crate::effect::Effect> { $($field: <$type as $crate::Build<'ctx, M, E>>::Builder),* } @@ -29,9 +29,8 @@ macro_rules! Build { $(pub const $field: usize = __Fields::$field as usize;)* } - #[derive(Debug)] - $vis enum Error { - $($field(<$type as $crate::BuilderTypes>::Error)),* + $vis enum Error<'ctx, M: 'ctx, E: $crate::effect::Effect> { + $($field(<<$type as $crate::Build<'ctx, M, E>>::Builder as $crate::BuilderTypes>::Error)),* } impl ::core::fmt::Display for Field { @@ -42,7 +41,15 @@ macro_rules! Build { } } - impl ::core::fmt::Display for Error { + impl<'ctx, M: 'ctx, E: $crate::effect::Effect> ::core::fmt::Debug for Error<'ctx, M, E> { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.write_str(match self { + $(Error::$field(_) => stringify!($field)),* + }) + } + } + + impl<'ctx, M: 'ctx, E: $crate::effect::Effect> ::core::fmt::Display for Error<'ctx, M, E> { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.write_str(match self { $(Error::$field(_) => stringify!($field)),* @@ -52,12 +59,12 @@ macro_rules! Build { $vis struct __Info; - impl<'ctx, M: 'ctx> $crate::builders::core::r#struct::StructTypeInfo<'ctx, M> for __Info { - type Builders<E: $crate::effect::Effect> = Builders<'ctx, M, E>; + impl<'ctx, M: 'ctx, E: $crate::effect::Effect> $crate::builders::core::r#struct::StructTypeInfo<'ctx, M, E> for __Info { + type Builders = Builders<'ctx, M, E>; type FieldMarker = Field; type T = $name; - type Error = Error; - type Seed = ($(<$type as $crate::BuilderTypes>::Seed),*); + type Error = Error<'ctx, M, E>; + type Seed = ($(<<$type as $crate::Build<'ctx, M, E>>::Builder as $crate::BuilderTypes>::Seed),*); type ValueT = $crate::any::OwnedStatic<$name>; const FIELD_COUNT: usize = { @@ -65,7 +72,7 @@ macro_rules! Build { }; #[inline(always)] - fn new_builders<'a, E: $crate::effect::Effect>(seed: Self::Seed) -> $crate::effect::ErasedEffective<'a, Self::Builders<E>, E> { + fn new_builders<'a>(seed: Self::Seed) -> $crate::effect::ErasedEffective<'a, Self::Builders, E> { let ($($field),*) = seed; use $crate::effect::EffectiveExt; @@ -79,7 +86,7 @@ macro_rules! Build { }) } - fn from_builders<'a, E: $crate::effect::Effect>(builders: Self::Builders<E>) -> $crate::effect::ErasedEffective<'a, Result<Self::T, Self::Error>, E> { + fn from_builders<'a>(builders: Self::Builders) -> $crate::effect::ErasedEffective<'a, Result<Self::T, Self::Error>, E> { use $crate::Builder; use $crate::effect::EffectiveExt; @@ -95,9 +102,9 @@ macro_rules! Build { }) } - fn as_visitor<'a, E: $crate::effect::Effect>( + fn as_visitor<'a>( marker: Self::FieldMarker, - builders: &'a mut Self::Builders<E>, + builders: &'a mut Self::Builders, ) -> $crate::protocol::DynVisitor<'a, 'ctx> { use $crate::Builder; diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index e2ed85c..bf2b8d2 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -79,6 +79,16 @@ impl<S> VisitResult<S> { VisitResult::Control(Flow::Err) => Some(Status::Err), } } + + pub fn map_skipped<R, F>(self, f: F) -> VisitResult<R> + where + F: FnOnce(S) -> R, + { + match self { + VisitResult::Skipped(s) => VisitResult::Skipped(f(s)), + VisitResult::Control(flow) => VisitResult::Control(flow), + } + } } pub trait EffectiveVisitExt<'lt>: Effective<'lt> { diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index 96eecb3..0c11fcd 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -43,7 +43,7 @@ where /// If [`Flow::Done`] is returned then the visitor doesn't need any more information and the walker /// should stop walking. /// If [`Flow::Break`] is returned then there was an error and the walker should stop walking. -pub fn visit_request_hint<'a, 'ctx, E: Effect>( +pub fn request_hint<'a, 'ctx, E: Effect>( visitor: DynVisitor<'a, 'ctx>, walker: DynWalker<'a, 'ctx>, ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs index 9f71868..ddf682d 100644 --- a/src/protocol/visitor/tag.rs +++ b/src/protocol/visitor/tag.rs @@ -21,6 +21,9 @@ pub mod tags { 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 type FieldNames = TagConst<{ Symbol::new("Field Names").to_int() }>; + pub type TypeName = TagConst<{ Symbol::new("Type Name").to_int() }>; + pub type TypeId = TagConst<{ Symbol::new("Type ID").to_int() }>; } pub trait TagKind: Copy + Send + Sync + 'static { diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs index e5a8a98..683436a 100644 --- a/src/protocol/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -5,10 +5,10 @@ //! to the walker about what it is expecting. use crate::{ - any::{AnyTrait, TypeName}, - effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _, Ss}, + any::TypeName, + effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _}, hkt::Marker, - protocol::{visitor::VisitResult, DynVisitor, DynWalker}, + protocol::{visitor::VisitResult, DynWalker}, Flow, }; @@ -49,7 +49,7 @@ impl<'a, 'ctx: 'a> Meta::LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()> for () { /// Meta information for the hint. /// /// This gives the visitor more information to work from when selecting a hint. -pub trait HintMeta: Send + Sync + 'static { +pub trait HintMeta: TypeName::MemberType + Send + Sync + 'static { /// Information known by the walker. /// /// This should be information easy to get without changing the state of the walker @@ -72,7 +72,7 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> { /// This should only be called once per [`RequestHint`]. fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>( &'this mut self, - visitor: DynVisitor<'visitor, 'ctx>, + visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>, hint: MetaHint<'hint, 'ctx, Protocol>, ) -> ErasedEffective<'e, Flow, Protocol::Effect> where @@ -110,14 +110,13 @@ pub fn hint_protocol< 'hint: 'e, 'e, Protocol: ?Sized + HintMeta, - V: AnyTrait<'ctx> + Ss, >( walker: DynWalker<'walker, 'ctx>, - visitor: &'visitor mut V, + visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>, hint: MetaHint<'hint, 'ctx, Protocol>, ) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect> { if let Some(object) = walker.0.upcast_mut::<HintProto<Protocol>>() { - object.hint(DynVisitor(visitor), hint).map(Into::into) + object.hint(visitor, hint).map(Into::into) } else { VisitResult::Skipped(()).ready() } diff --git a/src/transform.rs b/src/transform.rs index f055fcb..4d9e99d 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,6 +1,10 @@ +use futures::Future; + use crate::{ build::Builder, - effect::{blocking::Blocking, Effect, Effective, EffectiveExt, ErasedEffective}, + effect::{ + blocking::Blocking, r#async::Async, Effect, Effective, EffectiveExt, ErasedEffective, + }, Build, BuilderTypes, DefaultMode, Walk, Walker, WalkerTypes, }; @@ -70,6 +74,26 @@ pub trait BuildExt { } } + fn build_async<'ctx, W>( + walker: W, + ) -> impl Future<Output = Result<Self, BuildError<Self::Builder, W>>> + Send + Sync + where + Self: Build<'ctx, DefaultMode, Async>, + <Self::Builder as BuilderTypes>::Seed: Default, + W: Walker<'ctx, Async>, + { + async { + match transform::<Self::Builder, _, _>(Default::default(), walker) + .into_future() + .await + { + (Ok(value), _) => Ok(value), + (Err(err), Ok(_)) => Err(BuildError::Builder(err)), + (Err(build_err), Err(walker_err)) => Err(BuildError::Both(build_err, walker_err)), + } + } + } + fn new_builder<'ctx>() -> Self::Builder where Self: Build<'ctx, DefaultMode, Blocking>, @@ -82,13 +106,20 @@ pub trait BuildExt { impl<T> BuildExt for T {} pub trait WalkExt { - fn as_walker<'ctx: 'a, 'a, E: Effect>( + fn as_walker<'ctx: 'a, 'a>(&'a self) -> <&'a Self as Walk<'ctx, DefaultMode, Blocking>>::Walker + where + &'a Self: Walk<'ctx, DefaultMode, Blocking>, + { + Walk::into_walker(self).value() + } + + fn as_async_walker<'ctx: 'a, 'a>( &'a self, - ) -> <&'a Self as Walk<'ctx, DefaultMode, E>>::Walker + ) -> impl Future<Output = <&'a Self as Walk<'ctx, DefaultMode, Async>>::Walker> + Send + Sync where - &'a Self: Walk<'ctx, DefaultMode, E>, + &'a Self: Walk<'ctx, DefaultMode, Async>, { - Walk::into_walker(self) + Walk::into_walker(self).into_future() } #[allow(clippy::result_unit_err)] @@ -98,7 +129,7 @@ pub trait WalkExt { B: Builder<'ctx, Blocking>, { let mut builder = builder; - Walk::into_walker(self).walk(builder.as_visitor()); + let _ = Walk::into_walker(self).value().walk(builder.as_visitor()); match builder.build().value() { Ok(value) => Ok(value), _ => todo!(), diff --git a/src/walk.rs b/src/walk.rs index c16f5ae..0e02306 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -14,7 +14,9 @@ pub trait Walk<'ctx, M, E: Effect>: Sized { type Walker: Walker<'ctx, E>; #[must_use] - fn into_walker(self) -> Self::Walker; + fn into_walker<'e>(self) -> ErasedEffective<'e, Self::Walker, E> + where + Self: 'e; } pub trait WalkerTypes { diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs index 03929e5..890db00 100644 --- a/src/walk/walkers/core/bool.rs +++ b/src/walk/walkers/core/bool.rs @@ -1,12 +1,15 @@ -use crate::{effect::Effect, Walk, WalkerTypes}; +use crate::{ + effect::{Effect, ErasedEffective}, + Walk, WalkerTypes, +}; use super::value::ValueWalker; impl<'ctx, M, E: Effect> Walk<'ctx, M, E> for bool { type Walker = ValueWalker<bool>; - fn into_walker(self) -> Self::Walker { - ValueWalker::new(self) + fn into_walker<'e>(self) -> ErasedEffective<'e, Self::Walker, E> { + E::ready(ValueWalker::new(self)) } } @@ -18,8 +21,8 @@ impl WalkerTypes for bool { impl<'ctx, M, E: Effect> Walk<'ctx, M, E> for &'ctx bool { type Walker = ValueWalker<bool>; - fn into_walker(self) -> Self::Walker { - ValueWalker::new(*self) + fn into_walker<'e>(self) -> ErasedEffective<'e, Self::Walker, E> { + E::ready(ValueWalker::new(*self)) } } diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs index fc4607a..d98043d 100644 --- a/src/walk/walkers/core/struct.rs +++ b/src/walk/walkers/core/struct.rs @@ -8,15 +8,16 @@ use crate::{ never::Never, protocol::{ visitor::{ - visit_request_hint, visit_sequence, visit_tag, visit_value, EffectiveVisitExt as _, - RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto, - SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown, - ValueProto, VisitResult, + request_hint, tags, visit_sequence, visit_tag, visit_value, EffectiveVisitExt as _, + Recoverable, RecoverableKnown, RecoverableProto, RecoverableScope, Sequence, + SequenceKnown, SequenceProto, SequenceScope, Tag, TagConst, TagDyn, TagError, TagKnown, + TagProto, Value, ValueKnown, ValueProto, VisitResult, }, walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown}, DynVisitor, DynWalker, }, - Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME, + DynWalkerAdapter, Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, + TAG_TYPE_NAME, }; use super::{noop::NoopWalker, value::ValueWalker}; @@ -190,7 +191,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Recoverable<'ctx, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, RecoverableProto<E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -224,7 +225,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Tag<'ctx, tags::FieldNames, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -272,7 +273,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Tag<'ctx, tags::TypeName, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -320,7 +321,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Tag<'ctx, tags::Map, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -364,30 +365,20 @@ where #[inline(always)] fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>( &'this mut self, - visitor: DynVisitor<'visitor, 'ctx>, + visitor: &'visitor mut (dyn Tag<'ctx, tags::Struct, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ) -> ErasedEffective<'e, Flow, E> where 'ctx: 'this + 'visitor + 'hint + 'e, { E::as_ctx( - (self, visitor), + (visitor, DynWalkerAdapter::new(NoopWalker::new())), #[inline(always)] - |(this, visitor)| { - visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>( - TagConst, - visitor.cast(), - NoopWalker::new(), - ) - .map(|status| match status { - Err(err) => { - this.error = Some(StructWalkErrorKind::Tag(err)); - Flow::Err - } - Ok(VisitResult::Skipped(_)) => Flow::Continue, - Ok(VisitResult::Control(flow)) => flow, - }) - .cast() + |(visitor, noop_walker)| { + visitor + .visit(TagConst, noop_walker) + .map(|status| status.to_flow().unwrap_or(Flow::Continue)) + .cast() }, ) .remove_ctx() @@ -418,7 +409,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Tag<'ctx, tags::TypeId, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -466,45 +457,46 @@ where #[inline(always)] fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>( &'this mut self, - visitor: DynVisitor<'visitor, 'ctx>, - hint: MetaHint<'hint, 'ctx, TagProto<TagDyn, E>>, + _visitor: &'visitor mut (dyn Tag<'ctx, TagDyn, E> + Send + Sync), + _hint: MetaHint<'hint, 'ctx, TagProto<TagDyn, E>>, ) -> ErasedEffective<'e, Flow, E> where 'ctx: 'this + 'visitor + 'hint + 'e, { - match hint.kind.0 { - crate::TAG_TYPE_ID => { - Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>::hint( - self, - visitor, - TagHint { kind: TagConst }, - ) - } - crate::TAG_STRUCT => { - Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>::hint( - self, - visitor, - TagHint { kind: TagConst }, - ) - } - crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>::hint( - self, - visitor, - TagHint { kind: TagConst }, - ), - crate::TAG_TYPE_NAME => { - Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>::hint( - self, - visitor, - TagHint { kind: TagConst }, - ) - } - crate::TAG_FIELD_NAMES => Hint::< - 'ctx, - TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, - >::hint(self, visitor, TagHint { kind: TagConst }), - _ => E::ready(Flow::Continue), - } + todo!() + // match hint.kind.0 { + // crate::TAG_TYPE_ID => { + // Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>::hint( + // self, + // visitor, + // TagHint { kind: TagConst }, + // ) + // } + // crate::TAG_STRUCT => { + // Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>::hint( + // self, + // visitor, + // TagHint { kind: TagConst }, + // ) + // } + // crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>::hint( + // self, + // visitor, + // TagHint { kind: TagConst }, + // ), + // crate::TAG_TYPE_NAME => { + // Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>::hint( + // self, + // visitor, + // TagHint { kind: TagConst }, + // ) + // } + // crate::TAG_FIELD_NAMES => Hint::< + // 'ctx, + // TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, + // >::hint(self, visitor, TagHint { kind: TagConst }), + // _ => E::ready(Flow::Continue), + // } } #[inline(always)] @@ -533,7 +525,7 @@ where #[inline(always)] fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - _visitor: DynVisitor<'visitor, 'ctx>, + _visitor: &'visitor mut (dyn Value<'ctx, BorrowedStaticHrt<I::T>, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, ValueProto<BorrowedStaticHrt<I::T>, E>>, ) -> ErasedEffective<'e, Flow, E> where @@ -567,14 +559,15 @@ where fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>( &'this mut self, - visitor: DynVisitor<'visitor, 'ctx>, + visitor: &'visitor mut (dyn Sequence<'ctx, E> + Send + Sync), _hint: MetaHint<'hint, 'ctx, SequenceProto<E>>, ) -> ErasedEffective<'e, Flow, E> where 'ctx: 'this + 'visitor + 'hint + 'e, { E::as_ctx_map((self, visitor), |(this, visitor)| { - visit_sequence::<E>(visitor.cast(), *this) + visitor + .visit(*this) .map(|status| match status { VisitResult::Skipped(_) => Flow::Continue, VisitResult::Control(flow) => flow, @@ -661,7 +654,7 @@ where self.index = 0; E::as_ctx((self, visitor), |(this, visitor)| { - visit_request_hint::<E>(visitor.cast(), DynWalker(*this)) + request_hint::<E>(visitor.cast(), DynWalker(*this)) .map(VisitResult::unit_skipped) .cast() }) diff --git a/tests/builder_value.rs b/tests/builder_value.rs new file mode 100644 index 0000000..92f3450 --- /dev/null +++ b/tests/builder_value.rs @@ -0,0 +1,38 @@ +mod common; + +use treaty::{ + any::OwnedStatic, + effect::blocking::Blocking, + protocol::{ + visitor::{request_hint, ValueProto}, + DynWalker, + }, + BuildExt as _, Builder as _, Flow, +}; + +use crate::common::protocol::hint::MockHintWalker; + +#[test] +fn value_builder_gives_value_protocol_as_hint() { + // Create a builder for a i32. + let mut builder = i32::new_builder(); + + // Expect the value builder to hint the value protocol with a owned i32. + let mut walker = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new(); + walker.expect_hint().once().returning(|visitor, ()| { + // Fulfill the hint by visiting with a i32 value. + assert_eq!(visitor.visit(OwnedStatic(42)).value(), Flow::Done.into()); + + // We are done as the walker. + Flow::Done + }); + + // Request a hint from the i32 builder for what protocol to use. + assert_eq!( + request_hint::<Blocking>(builder.as_visitor(), DynWalker(&mut walker)).value(), + Flow::Done.into() + ); + + // The builder should have the value. + assert_eq!(builder.build().value().unwrap(), 42); +} diff --git a/tests/common/builder.rs b/tests/common/builder.rs index f86e4c7..d5a9ec3 100644 --- a/tests/common/builder.rs +++ b/tests/common/builder.rs @@ -104,4 +104,6 @@ impl<'ctx, Seed, Value, Error> AnyTrait<'ctx> for MockBuilder<Seed, Value, Error .as_mut() .and_then(|t| t.upcast_to_id_mut(id)) } + + type Available = () where Self: Sized; } diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs index 37606bc..1ca94dc 100644 --- a/tests/common/protocol/hint.rs +++ b/tests/common/protocol/hint.rs @@ -14,7 +14,7 @@ pub type KnownFactory<P> = mock! { pub HintWalker<P: HintMeta> { - pub fn hint<'a, 'b, 'c, 'ctx>(&'a mut self, visitor: DynVisitor<'b, 'ctx>, hint: MetaHint<'c, 'ctx, P>) -> Flow; + pub fn hint<'a, 'b, 'c, 'ctx>(&'a mut self, visitor: &'b mut TypeName::T<'b, 'ctx, P>, hint: MetaHint<'c, 'ctx, P>) -> Flow; pub fn known(&self) -> KnownFactory<P>; } @@ -30,7 +30,7 @@ any_trait! { impl<'ctx, P: HintMeta> Hint<'ctx, P> for MockHintWalker<P> { fn hint<'this, 'visitor, 'hint, 'e>( &'this mut self, - visitor: DynVisitor<'visitor, 'ctx>, + visitor: &'visitor mut TypeName::T<'visitor, 'ctx, P>, hint: MetaHint<'hint, 'ctx, P>, ) -> ErasedEffective<'e, Flow, P::Effect> where diff --git a/tests/common/walker.rs b/tests/common/walker.rs index abe7256..e5f2b7c 100644 --- a/tests/common/walker.rs +++ b/tests/common/walker.rs @@ -11,6 +11,7 @@ mock! { pub fn walk<'a, 'ctx>(self, visitor: DynVisitor<'a, 'ctx>) -> Result<Output, Error>; pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; + pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; } } @@ -56,4 +57,6 @@ impl<'ctx, Output, Error> AnyTrait<'ctx> for MockWalker<Output, Error> { .as_mut() .and_then(|t| t.upcast_to_id_mut(id)) } + + type Available = () where Self: Sized; } diff --git a/tests/protocol_walker_hint.rs b/tests/protocol_walker_hint.rs index 5c75f33..40c48e5 100644 --- a/tests/protocol_walker_hint.rs +++ b/tests/protocol_walker_hint.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use treaty::{ - any::TypeNameId, + any::{TypeName, TypeNameId}, effect::blocking::Blocking, protocol::walker::hint::{self, HintMeta, HintProto}, }; @@ -302,6 +302,14 @@ mod common; fn hint_proto() { struct MyProtocol; + impl<'a, 'ctx> TypeName::MemberTypeForLt<'a, 'ctx, &'a &'ctx ()> for MyProtocol { + type T = MyProtocol; + } + + impl<'a, 'ctx> TypeName::LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()> for MyProtocol { + type Higher = MyProtocol; + } + impl HintMeta for MyProtocol { type Known = (); type Hint = (); |