working serde walker with structs
| -rw-r--r-- | src/build/builders/core/bool.rs | 3 | ||||
| -rw-r--r-- | src/build/builders/core/struct.rs | 29 | ||||
| -rw-r--r-- | src/macros/build.rs | 8 | ||||
| -rw-r--r-- | src/walk/walkers/serde/deserializer.rs | 202 | ||||
| -rw-r--r-- | tests/builder_struct.rs | 10 | ||||
| -rw-r--r-- | tests/serde_deserializer.rs | 21 |
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 + } + } + ); } |