-rw-r--r--src/any.rs9
-rw-r--r--src/build.rs2
-rw-r--r--src/build/builders/core.rs1
-rw-r--r--src/build/builders/core/bool.rs100
-rw-r--r--src/build/builders/core/struct.rs86
-rw-r--r--src/build/builders/core/value.rs231
-rw-r--r--src/effect/async.rs2
-rw-r--r--src/effect/blocking.rs1
-rw-r--r--src/lib.rs34
-rw-r--r--src/macros/build.rs33
-rw-r--r--src/protocol/visitor.rs10
-rw-r--r--src/protocol/visitor/request_hint.rs2
-rw-r--r--src/protocol/visitor/tag.rs3
-rw-r--r--src/protocol/walker/hint.rs15
-rw-r--r--src/transform.rs43
-rw-r--r--src/walk.rs4
-rw-r--r--src/walk/walkers/core/bool.rs13
-rw-r--r--src/walk/walkers/core/struct.rs125
-rw-r--r--tests/builder_value.rs38
-rw-r--r--tests/common/builder.rs2
-rw-r--r--tests/common/protocol/hint.rs4
-rw-r--r--tests/common/walker.rs3
-rw-r--r--tests/protocol_walker_hint.rs10
23 files changed, 530 insertions, 241 deletions
diff --git a/src/any.rs b/src/any.rs
index 94a4b49..028f610 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -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>);
diff --git a/src/lib.rs b/src/lib.rs
index a371500..7f38206 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 = ();