working serde walker with structs
Konnor Andrews 2024-07-07
parent 8f8f43e · commit 9456642
-rw-r--r--src/build/builders/core/bool.rs3
-rw-r--r--src/build/builders/core/struct.rs29
-rw-r--r--src/macros/build.rs8
-rw-r--r--src/walk/walkers/serde/deserializer.rs202
-rw-r--r--tests/builder_struct.rs10
-rw-r--r--tests/serde_deserializer.rs21
6 files changed, 218 insertions, 55 deletions
diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs
index 8596fbb..b7ac958 100644
--- a/src/build/builders/core/bool.rs
+++ b/src/build/builders/core/bool.rs
@@ -2,9 +2,9 @@ use super::value::{Cloneable, ValueBuilder};
use crate::any::{
BorrowedMutStatic, BorrowedStatic, OwnedStatic, TempBorrowedMutStatic, TempBorrowedStatic,
};
+use crate::Builder;
use effectful::bound::{Dynamic, IsSync};
use effectful::environment::{DynBind, Environment};
-use crate::Builder;
macro_rules! value_builder {
[$($ty:ty),*] => {
@@ -23,3 +23,4 @@ value_builder![f32, f64];
value_builder![char];
value_builder![bool];
value_builder![()];
+value_builder![String];
diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs
index e9abc9c..555314d 100644
--- a/src/build/builders/core/struct.rs
+++ b/src/build/builders/core/struct.rs
@@ -211,6 +211,7 @@ where
Dynamic<Info::T>: DynBind<E>,
Info: StructTypeInfo<'ctx, Mode, E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'a> Dynamic<&'a Info::T>: DynBind<E>,
for<'b, 'c> Dynamic<TypeName::T<'b, 'c, Info::ValueT, E>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
@@ -262,6 +263,7 @@ where
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
for<'a> Dynamic<&'a Info::T>: DynBind<E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'b, 'c> Dynamic<TypeName::T<'b, 'c, Info::ValueT, E>>: DynBind<E>,
for<'b> Dynamic<TempBorrowedStatic<'b, str>>: DynBind<E>,
for<'b, 'c> Dynamic<&'b TypeName::T<'b, 'c, Info::ValueT, E>>: DynBind<E>,
@@ -288,6 +290,7 @@ any_trait! {
Info: StructTypeInfo<'ctx, Mode, E>,
Dynamic<Info::T>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'b, 'c> Dynamic<TypeName::T<'b, 'c, Info::ValueT, E>>: DynBind<E>,
for<'b, 'c> Dynamic<&'b TypeName::T<'b, 'c, Info::ValueT, E>>: DynBind<E>,
for<'b> Dynamic<TempBorrowedStatic<'b, str>>: DynBind<E>,
@@ -307,6 +310,7 @@ where
Dynamic<OwnedStatic<usize>>: DynBind<E>,
for<'b> Dynamic<TempBorrowedStatic<'b, str>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
E: Environment,
{
#[inline(always)]
@@ -463,6 +467,7 @@ where
Info: StructTypeInfo<'ctx, Mode, E>,
for<'b> Dynamic<TempBorrowedStatic<'b, str>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
E: Environment,
{
@@ -571,6 +576,7 @@ any_trait! {
I: StructTypeInfo<'ctx, M, E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'b> Dynamic<TempBorrowedStatic<'b, str>>: DynBind<E>,
}
@@ -580,6 +586,7 @@ where
I: StructTypeInfo<'ctx, M, E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
{
fn visit<'a: 'c, 'b: 'c, 'c>(
@@ -615,11 +622,13 @@ any_trait! {
ValueProto<OwnedStatic<usize>, E>,
ValueProto<TempBorrowedStaticHrt<str>, E>,
ValueProto<OwnedStatic<&'static str>, E>,
+ ValueProto<OwnedStatic<String>, E>,
] where
E: Environment,
I: StructTypeInfo<'ctx, M, E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
Dynamic<OwnedStatic<&'static str>>: DynBind<E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
}
@@ -682,3 +691,23 @@ where
E::value(VisitResult::Control(Flow::Done)).cast()
}
}
+
+impl<'ctx, I, M, E> Value<'ctx, OwnedStatic<String>, E> for NameVisitor<'ctx, I, M, E>
+where
+ E: Environment,
+ I: StructTypeInfo<'ctx, M, E>,
+ Dynamic<OwnedStatic<String>>: DynBind<E>,
+{
+ fn visit<'a>(
+ &'a mut self,
+ OwnedStatic(name): TypeName::T<'a, 'ctx, OwnedStatic<String>, E>,
+ ) -> NativeForm<'a, VisitResult<Dynamic<TypeName::T<'a, 'ctx, OwnedStatic<String>, E>>>, E>
+ where
+ TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>, E>: Sized,
+ 'ctx: 'a,
+ {
+ self.field_marker = I::marker_from_name(&name);
+
+ E::value(VisitResult::Control(Flow::Done)).cast()
+ }
+}
diff --git a/src/macros/build.rs b/src/macros/build.rs
index a0ad6ab..e655aae 100644
--- a/src/macros/build.rs
+++ b/src/macros/build.rs
@@ -13,6 +13,7 @@ macro_rules! Build {
where
effectful::bound::Dynamic<$name>: effectful::environment::DynBind<E>,
$($type: $crate::Build<'ctx, M, E>,)*
+ $(effectful::bound::Dynamic<$type>: effectful::environment::DynBind<E>,)*
$crate::builders::core::r#struct::StructBuilder<'ctx, __Info, M, E>: $crate::Builder<'ctx, E, Value = Self>
{
type Builder = $crate::builders::core::r#struct::StructBuilder<'ctx, __Info, M, E>;
@@ -83,7 +84,8 @@ macro_rules! Build {
impl<'ctx, M: 'ctx, E: effectful::environment::Environment> $crate::builders::core::r#struct::StructTypeInfo<'ctx, M, E> for __Info
where
effectful::bound::Dynamic<$name>: effectful::environment::DynBind<E>,
- $($type: $crate::Build<'ctx, M, E>),*
+ $($type: $crate::Build<'ctx, M, E>,)*
+ $(effectful::bound::Dynamic<$type>: effectful::environment::DynBind<E>),*
{
type Builders = Builders<'ctx, M, E>;
type FieldMarker = Field;
@@ -120,10 +122,10 @@ macro_rules! Build {
effectful::effective::try_join(
(
- $(builders.$field.build().map((), |_, x| x.map(|x| <<$type as Build<'ctx, M, E>>::Builder as BuilderTypes<E>>::unwrap_output(x)).map_err(Error::$field)),)*
+ $(builders.$field.build().map((), |_, x| x.map(|x| effectful::bound::Dynamic(<<$type as Build<'ctx, M, E>>::Builder as BuilderTypes<E>>::unwrap_output(x))).map_err(Error::$field)),)*
)
).map((), |_, result| match result {
- Ok(($($field,)*)) => Ok(effectful::bound::Dynamic($name {
+ Ok(($(effectful::bound::Dynamic($field),)*)) => Ok(effectful::bound::Dynamic($name {
$($field),*
})),
Err(err) => Err(err)
diff --git a/src/walk/walkers/serde/deserializer.rs b/src/walk/walkers/serde/deserializer.rs
index 8818102..32e58f1 100644
--- a/src/walk/walkers/serde/deserializer.rs
+++ b/src/walk/walkers/serde/deserializer.rs
@@ -1,11 +1,15 @@
+use crate::walkers::core::noop::NoopWalker;
use effectful::{
- bound::{Dynamic, No},
+ bound::{Dynamic, HasSendAndSync, No},
effective::Effective,
effective::NativeEffective,
environment::{DynBind, EnvConfig, Environment, NativeForm},
SendSync,
};
-use serde::{de::MapAccess, Deserializer};
+use serde::{
+ de::{DeserializeSeed, MapAccess},
+ Deserializer,
+};
use crate::{
any::{BorrowedStaticHrt, OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName},
@@ -13,8 +17,8 @@ use crate::{
hkt::Marker,
protocol::{
visitor::{
- request_hint, tags, visit_sequence, visit_value, EffectiveVisitExt as _, SequenceScope,
- TagConst, TagKnown, TagProto, ValueKnown, ValueProto, VisitResult,
+ request_hint, tags, visit_sequence, visit_tag, visit_value, EffectiveVisitExt as _,
+ SequenceScope, TagConst, TagKnown, TagProto, ValueKnown, ValueProto, VisitResult,
},
walker::hint::{DynVisitorWith, Hint, HintMeta, HintProto, MetaHint, MetaKnown},
DynVisitor, DynWalker,
@@ -69,19 +73,19 @@ where
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match &self.inner {
- VisitorError::u8(err) => write!(f, "{}", err),
- VisitorError::u16(err) => write!(f, "{}", err),
- VisitorError::u32(err) => write!(f, "{}", err),
- VisitorError::u64(err) => write!(f, "{}", err),
- VisitorError::u128(err) => write!(f, "{}", err),
- VisitorError::usize(err) => write!(f, "{}", err),
- VisitorError::i8(err) => write!(f, "{}", err),
- VisitorError::i16(err) => write!(f, "{}", err),
- VisitorError::i32(err) => write!(f, "{}", err),
- VisitorError::i64(err) => write!(f, "{}", err),
- VisitorError::i128(err) => write!(f, "{}", err),
- VisitorError::isize(err) => write!(f, "{}", err),
- VisitorError::Serde(err) => write!(f, "{}", err.0),
+ VisitorError::u8(err) => write!(f, "u8 {}", err),
+ VisitorError::u16(err) => write!(f, "u16 {}", err),
+ VisitorError::u32(err) => write!(f, "u32 {}", err),
+ VisitorError::u64(err) => write!(f, "u64 {}", err),
+ VisitorError::u128(err) => write!(f, "u128 {}", err),
+ VisitorError::usize(err) => write!(f, "usize {}", err),
+ VisitorError::i8(err) => write!(f, "i8 {}", err),
+ VisitorError::i16(err) => write!(f, "i16 {}", err),
+ VisitorError::i32(err) => write!(f, "i32 {}", err),
+ VisitorError::i64(err) => write!(f, "i64 {}", err),
+ VisitorError::i128(err) => write!(f, "i128 {}", err),
+ VisitorError::isize(err) => write!(f, "isize {}", err),
+ VisitorError::Serde(err) => write!(f, "Serde {}", err.0),
}
}
}
@@ -97,7 +101,7 @@ where
impl<'ctx, T, E: Environment> Walker<'ctx, E> for DeserializerWalker<'ctx, T, E>
where
- T: Deserializer<'ctx> + 'ctx,
+ T: Deserializer<'ctx>,
E: EnvConfig<NeedSend = No, NeedSync = No>,
{
type Error = DeserializerWalkerError<'ctx, T>;
@@ -120,8 +124,9 @@ where
.cast()
})
.if_not_finished((), |_, (this, visitor)| {
- this.call_deserialize(|deserializer| {
- deserializer.deserialize_any(Visitor::<T, E>::new(visitor.cast(), "any"))
+ this.call_deserialize(visitor.cast(), |visitor, deserializer| {
+ let x = deserializer.deserialize_any(Visitor::<T, E>::new(visitor, "any"));
+ x.map(|x| x.cast())
})
.cast()
})
@@ -138,41 +143,48 @@ where
any_trait! {
impl['ctx, T][E] DeserializerWalker<'ctx, T, E> = [
HintProto<ValueProto<OwnedStatic<bool>, E>>,
- HintProto<ValueProto<OwnedStatic<i8>, E>>,
- HintProto<ValueProto<OwnedStatic<i16>, E>>,
- HintProto<ValueProto<OwnedStatic<i32>, E>>,
- HintProto<ValueProto<OwnedStatic<i64>, E>>,
- HintProto<ValueProto<OwnedStatic<i128>, E>>,
- HintProto<ValueProto<OwnedStatic<u8>, E>>,
- HintProto<ValueProto<OwnedStatic<u16>, E>>,
- HintProto<ValueProto<OwnedStatic<u32>, E>>,
- HintProto<ValueProto<OwnedStatic<u64>, E>>,
- HintProto<ValueProto<OwnedStatic<u128>, E>>,
- HintProto<ValueProto<OwnedStatic<char>, E>>,
- HintProto<TagProto<tags::Map, E>>,
+ // HintProto<ValueProto<OwnedStatic<i8>, E>>,
+ // HintProto<ValueProto<OwnedStatic<i16>, E>>,
+ // HintProto<ValueProto<OwnedStatic<i32>, E>>,
+ // HintProto<ValueProto<OwnedStatic<i64>, E>>,
+ // HintProto<ValueProto<OwnedStatic<i128>, E>>,
+ // HintProto<ValueProto<OwnedStatic<u8>, E>>,
+ // HintProto<ValueProto<OwnedStatic<u16>, E>>,
+ // HintProto<ValueProto<OwnedStatic<u32>, E>>,
+ // HintProto<ValueProto<OwnedStatic<u64>, E>>,
+ // HintProto<ValueProto<OwnedStatic<u128>, E>>,
+ // HintProto<ValueProto<OwnedStatic<char>, E>>,
+ // HintProto<TagProto<tags::Map, E>>,
] where
- T: Deserializer<'ctx> + 'ctx,
+ T: Deserializer<'ctx>,
E: Environment<NeedSend = No, NeedSync = No>
}
impl<'ctx, T, E: Environment> DeserializerWalker<'ctx, T, E>
where
- T: Deserializer<'ctx> + 'ctx,
+ T: Deserializer<'ctx>,
E: EnvConfig<NeedSend = No, NeedSync = No>,
{
- fn call_deserialize<'visitor: 'e, 'e, F>(&'e mut self, f: F) -> NativeForm<'e, VisitResult, E>
- where
- 'ctx: 'visitor,
- F: FnOnce(
+ fn call_deserialize<'this: 'e, 'e, Cap>(
+ &'this mut self,
+ cap: Cap,
+ f: fn(
+ Cap,
T,
) -> Result<
- NativeForm<'visitor, (Option<VisitorError<'ctx, T>>, VisitResult), E>,
+ NativeForm<'e, (Option<VisitorError<'ctx, T>>, VisitResult), E, (&'ctx (), Cap)>,
T::Error,
>,
+ ) -> NativeForm<'e, VisitResult, E>
+ where
+ 'ctx: 'this,
+ Cap: DynBind<E> + 'e,
{
match core::mem::replace(&mut self.inner, Inner::Temp) {
Inner::Init(deserializer) => {
- match f(deserializer.0) {
+ // E::value(cap)
+ // .update((HasSendAndSync(f), self, deserializer), |(HasSendAndSync(f), this, deserializer), cap| {
+ match f(cap, deserializer.0) {
Ok(eff) => eff
.map(self, |this, result| match result {
(None, result) => {
@@ -185,7 +197,7 @@ where
Flow::Err.into()
}
})
- .cast::<()>(),
+ .cast(),
Err(err) => {
self.inner = Inner::Error(DeserializerWalkerError {
inner: VisitorError::Serde(Dynamic(err)),
@@ -193,6 +205,9 @@ where
E::value(Flow::Err.into()).cast()
}
}
+ // })
+ // .map((), |_, (_, x)| x)
+ // .cast()
}
inner => {
// We really shouldn't be in this situation...
@@ -207,7 +222,7 @@ macro_rules! impl_hints {
(<$ctx:lifetime, $T:ident, $E:ident> $($proto:ty => $method:ident: $type:ty),* $(,)?) => {
$(impl<$ctx, $T, $E: Environment> Hint<$ctx, $proto> for DeserializerWalker<$ctx, $T, $E>
where
- $T: Deserializer<$ctx> + $ctx,
+ $T: Deserializer<$ctx>,
$E: EnvConfig<NeedSend = No, NeedSync = No>
{
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
@@ -218,7 +233,16 @@ macro_rules! impl_hints {
where
$ctx: 'this + 'visitor + 'hint + 'e,
{
- self.call_deserialize(|deserializer| deserializer.$method(Visitor::<$T, $E>::new(visitor.into_inner(), stringify!($type))))
+ $E::value((self, visitor))
+ .update((), |_, (this, visitor)| {
+ this.call_deserialize(visitor, move |visitor, deserializer| {
+ let x = deserializer.$method(Visitor::<$T, $E>::new(visitor.cast(), stringify!($type)));
+ x.map(|x| x.cast())
+ })
+ .cast()
+ })
+ .map((), |_, (_, x)| x)
+ .cast()
}
fn known<'a>(
@@ -258,7 +282,7 @@ impl_hints! {
impl<'ctx, T, E: Environment> Hint<'ctx, TagProto<tags::Map, E>> for DeserializerWalker<'ctx, T, E>
where
- T: Deserializer<'ctx> + 'ctx,
+ T: Deserializer<'ctx>,
E: EnvConfig<NeedSend = No, NeedSync = No>,
{
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
@@ -399,10 +423,13 @@ where
A: MapAccess<'ctx>,
{
E::value((self, MapScope { map: Dynamic(map) })).update((), |_, (this, scope)| {
+ // Need to notify the visitor we are doing a map instead of just a sequence.
+ visit_tag::<tags::Map, E, _>(TagConst, this.visitor.cast(), NoopWalker::new());
+
visit_sequence(this.visitor.cast(), scope).cast()
});
- todo!()
+ Ok(E::value((None, VisitResult::Control(Flow::Done))).cast())
}
}
@@ -422,11 +449,92 @@ where
fn next<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
- visitor: DynVisitor<'b, 'ctx, E>,
+ mut visitor: DynVisitor<'b, 'ctx, E>,
) -> NativeForm<'c, Flow, E>
where
'ctx: 'c + 'a + 'b,
{
- todo!()
+ // need to convert visitor into a serde key and value deserializer
+ // match self.map.0.next_entry() {
+ // Ok(Some((key, value))) => {},
+ // Ok(None) => {},
+ // Err(err) => {},
+ // }
+
+ // let key = self.map.0.next_key(); // assume we have done this
+ // let value = self.map.0.next_value_seed(()); // we want value here to be an
+ // effective.
+ let x = self.map.0.next_key_seed(KeyDeserialize {
+ visitor: visitor.cast(),
+ });
+ // dbg!(&x);
+
+ if x.unwrap().is_some() {
+ // There is another item.
+ let x = self.map.0.next_value_seed(ValueDeserialize { visitor });
+ // dbg!(x);
+ E::value(Flow::Continue).cast()
+ } else {
+ E::value(Flow::Done).cast()
+ }
+ }
+}
+
+struct KeyDeserialize<'a, 'ctx, E: Environment> {
+ visitor: DynVisitor<'a, 'ctx, E>,
+}
+
+impl<'a, 'ctx: 'a, E: Environment> DeserializeSeed<'ctx> for KeyDeserialize<'a, 'ctx, E>
+where
+ E: EnvConfig<NeedSend = No, NeedSync = No>,
+{
+ type Value = ();
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'ctx>,
+ {
+ // We have a deserializer and we know how to handle those!
+ let walker = DeserializerWalker::<'_, _, E>::new(deserializer);
+
+ // We can't return an effective that stores D as we don't know D's lifetime,
+ // so we must block instead. This should be fine as serde itself isn't async
+ // normally.
+
+ let x = visit_tag::<tags::Key, E, _>(TagConst, self.visitor.cast(), walker)
+ .map((), |_, result| match result {
+ Ok(visit) => visit.unit_skipped(),
+ Err(_) => Flow::Err.into(),
+ })
+ .wait();
+
+ // dbg!(x);
+
+ Ok(())
+ }
+}
+
+struct ValueDeserialize<'a, 'ctx, E: Environment> {
+ visitor: DynVisitor<'a, 'ctx, E>,
+}
+
+impl<'a, 'ctx, E: Environment> DeserializeSeed<'ctx> for ValueDeserialize<'a, 'ctx, E>
+where
+ E: EnvConfig<NeedSend = No, NeedSync = No>,
+{
+ type Value = ();
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'ctx>,
+ {
+ // We have a deserializer and we know how to handle those!
+ let walker = DeserializerWalker::<'_, _, E>::new(deserializer);
+
+ let x = walker.walk(self.visitor).wait();
+
+ dbg!(x);
+
+ Ok(())
}
}
diff --git a/tests/builder_struct.rs b/tests/builder_struct.rs
index 1149b9b..219c069 100644
--- a/tests/builder_struct.rs
+++ b/tests/builder_struct.rs
@@ -61,7 +61,10 @@ fn a_struct_builder_can_build_from_a_sequence_of_field_values() {
));
// The builder should be able to build a instance of the struct.
- assert_eq!(builder.build().into_value().unwrap().0, X { a: true, b: false });
+ assert_eq!(
+ builder.build().into_value().unwrap().0,
+ X { a: true, b: false }
+ );
}
#[test]
@@ -146,5 +149,8 @@ fn a_struct_builder_can_build_from_a_sequence_of_keyed_values() {
);
// The struct is built as the mock walker above makes it.
- assert_eq!(builder.build().into_value().unwrap().0, X { a: false, b: true });
+ assert_eq!(
+ builder.build().into_value().unwrap().0,
+ X { a: false, b: true }
+ );
}
diff --git a/tests/serde_deserializer.rs b/tests/serde_deserializer.rs
index acb2e56..6d50279 100644
--- a/tests/serde_deserializer.rs
+++ b/tests/serde_deserializer.rs
@@ -28,13 +28,30 @@ fn demo2() {
struct X {
a: bool,
b: i64,
+ c: Y,
+}
+
+#[derive(Build!, Debug, PartialEq)]
+struct Y {
+ name: String,
+ age: u8,
}
#[test]
fn demo3() {
- let x = json!({ "a": true, "b": 42 });
+ let x = json!({ "a": true, "b": 42, "c": { "name": "hi", "age": 200 }});
let y = X::build(DeserializerWalker::new(x));
- assert_eq!(y.unwrap(), X { a: true, b: 42 });
+ assert_eq!(
+ y.unwrap(),
+ X {
+ a: true,
+ b: 42,
+ c: Y {
+ name: "hi".into(),
+ age: 200
+ }
+ }
+ );
}