Diffstat (limited to 'src/walk/walkers/serde/deserializer.rs')
-rw-r--r--src/walk/walkers/serde/deserializer.rs345
1 files changed, 333 insertions, 12 deletions
diff --git a/src/walk/walkers/serde/deserializer.rs b/src/walk/walkers/serde/deserializer.rs
index cabffab..f5d9628 100644
--- a/src/walk/walkers/serde/deserializer.rs
+++ b/src/walk/walkers/serde/deserializer.rs
@@ -1,15 +1,336 @@
-use crate::{effect::Effect, Walker};
+use serde::Deserializer;
-pub struct DeserializerWalker<T> {
- deserializer: T,
+use crate::{
+ any::{BorrowedStaticHrt, OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName}, any_trait, effect::{
+ BlockOn, Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss,
+ }, hkt::Marker, protocol::{
+ visitor::{request_hint, visit_value, ValueKnown, ValueProto, VisitResult},
+ walker::hint::{DynVisitorWith, Hint, HintMeta, HintProto, MetaHint, MetaKnown},
+ DynVisitor, DynWalker,
+ }, walkers::core::int::IntegerWalkerError, Flow, Walker
+};
+
+pub struct DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ inner: Inner<'ctx, T>,
+ _marker: Marker<E>,
+}
+
+enum Inner<'ctx, T>
+where
+ T: Deserializer<'ctx>,
+{
+ Temp,
+ Init(T),
+ Error(DeserializerWalkerError<'ctx, T>),
+ Done,
+}
+
+impl<'ctx, T, E: Effect> DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ pub fn new(deserializer: T) -> Self {
+ Self {
+ inner: Inner::Init(deserializer),
+ _marker: Default::default(),
+ }
+ }
+}
+
+pub struct DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ inner: VisitorError<'ctx, T>,
+}
+
+impl<'ctx, T> core::fmt::Debug for DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ 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),
+ }
+ }
+}
+
+impl<'ctx, T> core::fmt::Display for DeserializerWalkerError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl<'ctx, T, E: Effect> Walker<'ctx, E> for DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx> + Ss,
+ T::Error: Ss,
+{
+ type Error = DeserializerWalkerError<'ctx, T>;
+
+ type Output = ();
+
+ fn walk<'visitor: 'effect, 'effect>(
+ self,
+ visitor: DynVisitor<'visitor, 'ctx>,
+ ) -> ErasedEffective<'effect, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'effect,
+ {
+ E::as_ctx((self, visitor), |(this, visitor)| {
+ // Serde deserializers usually prefer that a hint method is called rather than _any.
+ // As such we need to ask the visitor for a hint first.
+ request_hint::<E>(visitor.cast(), DynWalker(this))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .map(|((this, _), _)| match this.inner {
+ Inner::Temp => todo!(),
+ Inner::Init(_) => todo!(),
+ Inner::Error(err) => Err(err),
+ Inner::Done => Ok(()),
+ })
+ }
+}
+
+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>>,
+ ] where
+ T: Deserializer<'ctx> + Ss,
+ T::Error: Ss,
+ E: Effect
+}
+
+impl<'ctx, T, E: Effect> DeserializerWalker<'ctx, T, E>
+where
+ T: Deserializer<'ctx>,
+{
+ fn call_deserialize<'visitor, 'e, F>(&mut self, f: F) -> ErasedEffective<'e, VisitResult, E>
+ where
+ F: FnOnce(T) -> Result<(Option<VisitorError<'ctx, T>>, VisitResult), T::Error>,
+ {
+ match core::mem::replace(&mut self.inner, Inner::Temp) {
+ Inner::Init(deserializer) => {
+ match f(deserializer) {
+ Ok((None, result)) => {
+ // Return the flow the visitor decided on.
+ self.inner = Inner::Done;
+ E::ready(result)
+ }
+ Ok((Some(err), _)) => {
+ self.inner = Inner::Error(DeserializerWalkerError { inner: err});
+ E::ready(Flow::Err.into())
+ }
+ Err(err) => {
+ // There was an error from serde so record it and signal an error with the
+ // flow.
+ self.inner = Inner::Error(DeserializerWalkerError { inner: VisitorError::Serde(err) });
+ E::ready(Flow::Err.into())
+ }
+ }
+ }
+ inner => {
+ // We really shouldn't be in this situation...
+ self.inner = inner;
+ E::ready(VisitResult::Skipped(()))
+ }
+ }
+ }
+}
+
+macro_rules! impl_hints {
+ (<$ctx:lifetime, $T:ident, $E:ident> $($proto:ty => $method:ident: $type:ty),* $(,)?) => {
+ $(impl<$ctx, $T, $E: Effect> Hint<$ctx, $proto> for DeserializerWalker<$ctx, $T, $E>
+ where
+ $T: Deserializer<$ctx>,
+ {
+ fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
+ &'this mut self,
+ visitor: DynVisitorWith<'visitor, $ctx, $proto>,
+ _hint: MetaHint<'hint, $ctx, $proto>,
+ ) -> ErasedEffective<'e, VisitResult, $E>
+ where
+ $ctx: 'this + 'visitor + 'hint + 'e,
+ {
+ self.call_deserialize(|deserializer| deserializer.$method(Visitor::new(visitor, stringify!($type))))
+ }
+
+ fn known<'a>(
+ &'a mut self,
+ _hint: &'a MetaHint<'a, 'ctx, $proto>,
+ ) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, $proto>, ()>, $E> {
+ E::ready(Ok(ValueKnown { preview: None }))
+ }
+ })*
+ };
+}
+
+impl_hints! {
+ <'ctx, T, E>
+ ValueProto<OwnedStatic<bool>, E> => deserialize_bool: bool,
+ ValueProto<OwnedStatic<i8>, E> => deserialize_i8: i8,
+ ValueProto<OwnedStatic<i16>, E> => deserialize_i16: i16,
+ ValueProto<OwnedStatic<i32>, E> => deserialize_i32: i32,
+ ValueProto<OwnedStatic<i64>, E> => deserialize_i64: i64,
+ ValueProto<OwnedStatic<i128>, E> => deserialize_i128: i128,
+ ValueProto<OwnedStatic<u8>, E> => deserialize_u8: u8,
+ ValueProto<OwnedStatic<u16>, E> => deserialize_u16: u16,
+ ValueProto<OwnedStatic<u32>, E> => deserialize_u32: u32,
+ ValueProto<OwnedStatic<u64>, E> => deserialize_u64: u64,
+ ValueProto<OwnedStatic<u128>, E> => deserialize_u128: u128,
+ ValueProto<OwnedStatic<f32>, E> => deserialize_f32: f32,
+ ValueProto<OwnedStatic<f64>, E> => deserialize_f64: f64,
+ ValueProto<OwnedStatic<char>, E> => deserialize_char: char,
+ ValueProto<TempBorrowedStaticHrt<str>, E> => deserialize_str: &str,
+ ValueProto<BorrowedStaticHrt<str>, E> => deserialize_str: &str,
+ ValueProto<OwnedStatic<String>, E> => deserialize_string: String,
+ ValueProto<TempBorrowedStaticHrt<[u8]>, E> => deserialize_bytes: &[u8],
+ ValueProto<BorrowedStaticHrt<[u8]>, E> => deserialize_bytes: &[u8],
+ ValueProto<OwnedStatic<Vec<u8>>, E> => deserialize_byte_buf: Vec<u8>,
+ // ...
+}
+
+#[allow(non_camel_case_types, unused)]
+enum VisitorError<'ctx, T>
+where
+ T: Deserializer<'ctx>
+{
+ u8(IntegerWalkerError<u8>),
+ u16(IntegerWalkerError<u16>),
+ u32(IntegerWalkerError<u32>),
+ u64(IntegerWalkerError<u64>),
+ u128(IntegerWalkerError<u128>),
+ usize(IntegerWalkerError<usize>),
+ i8(IntegerWalkerError<i8>),
+ i16(IntegerWalkerError<i16>),
+ i32(IntegerWalkerError<i32>),
+ i64(IntegerWalkerError<i64>),
+ i128(IntegerWalkerError<i128>),
+ isize(IntegerWalkerError<isize>),
+ Serde(T::Error),
+}
+
+struct Visitor<'temp, 'ctx, T, E>
+where
+ T: Deserializer<'ctx>
+{
+ wanted: &'static str,
+ visitor: DynVisitor<'temp, 'ctx>,
+ error: Option<VisitorError<'ctx, T>>,
+ _marker: Marker<(T, E)>,
+}
+
+impl<'temp, 'ctx, T, E> Visitor<'temp, 'ctx, T, E>
+where
+ T: Deserializer<'ctx>
+{
+ pub fn new<Protocol: HintMeta<Effect = E>>(
+ visitor: DynVisitorWith<'temp, 'ctx, Protocol>,
+ wanted: &'static str,
+ ) -> Self {
+ Self {
+ wanted,
+ visitor: visitor.into_inner(),
+ error: None,
+ _marker: Default::default(),
+ }
+ }
}
-// impl<'ctx, T, E: Effect> Walker<'ctx, E> for DeserializerWalker<T> {
-//
-// }
-//
-// impl<T> WalkerTypes for DeserializerWalker<T> {
-// type Error;
-//
-// type Output;
-// }
+macro_rules! impl_visits {
+ (@owned $($method:ident: $type:ty),* $(,)?) => {
+ $(fn $method<Err>(mut self, v: $type) -> Result<Self::Value, Err>
+ where
+ Err: serde::de::Error,
+ {
+ // Visit the treaty visitor with the value serde gave.
+ let result = visit_value::<_, E>(self.visitor.cast(), OwnedStatic(v));
+
+ // Because serde is sync we need to block on the effective here.
+ // We use the block on impl the effect context says to use.
+ let value = E::BlockOn::block_on(result.into_future());
+
+ // If the visitor skipped the value we just report a continue.
+ Ok((self.error, value.unit_skipped()))
+ })*
+ };
+ // Many serde deserializers (like serde_json) don't follow the hint given when visiting.
+ // So we need to use the full integer walker that can visit all the types.
+ (@int $($method:ident: $type:ident),* $(,)?) => {
+ $(fn $method<Err>(mut self, v: $type) -> Result<Self::Value, Err>
+ where
+ Err: serde::de::Error,
+ {
+ let result = $crate::walkers::core::int::IntegerWalker::<_, E>::new(v).walk(self.visitor.cast());
+
+ // Because serde is sync we need to block on the effective here.
+ // We use the block on impl the effect context says to use.
+ if let Err(err) = E::BlockOn::block_on(result.into_future()) {
+ self.error = Some(VisitorError::$type(err))
+ }
+
+ Ok((self.error, VisitResult::Control(Flow::Done)))
+ })*
+ };
+}
+
+impl<'temp, 'ctx, T: Deserializer<'ctx>, E: Effect> serde::de::Visitor<'ctx> for Visitor<'temp, 'ctx, T, E> {
+ type Value = (Option<VisitorError<'ctx, T>>, VisitResult);
+
+ fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ formatter.write_str(&self.wanted)
+ }
+
+ impl_visits! {
+ @owned
+ visit_bool: bool,
+ visit_char: char,
+ visit_string: String,
+ visit_byte_buf: Vec<u8>,
+ // ...
+ }
+
+ impl_visits! {
+ @int
+ visit_i8: i8,
+ visit_i16: i16,
+ visit_i32: i32,
+ visit_i64: i64,
+ visit_i128: i128,
+ visit_u8: u8,
+ visit_u16: u16,
+ visit_u32: u32,
+ visit_u64: u64,
+ visit_u128: u128,
+ }
+}