Skip to content

Instantly share code, notes, and snippets.

@tesaguri
Created February 12, 2023 12:29
Show Gist options
  • Save tesaguri/e45f1a829fe7bbb74bf009312c37d82f to your computer and use it in GitHub Desktop.
Save tesaguri/e45f1a829fe7bbb74bf009312c37d82f to your computer and use it in GitHub Desktop.
An (unsuccessful) attempt to deserialize async response body using a type-erased `DeserializeSeed` impl
[package]
name = "erased-deserialize-seed-test"
version = "0.0.0"
edition = "2021"
publish = false
[dependencies]
erased-serde = "0.3"
serde = "1"
serde_json = "1"
pub mod erased {
use serde::de;
pub trait DeserializeSeed<'de> {
type Value;
fn erased_deserialize(
&mut self,
deserializer: &mut dyn erased_serde::Deserializer<'de>,
) -> erased_serde::Result<Self::Value>;
}
pub fn erase_seed<'de, T: de::DeserializeSeed<'de>>(
seed: T,
) -> self::erase::DeserializeSeed<T> {
self::erase::DeserializeSeed { state: Some(seed) }
}
mod erase {
use serde::de;
pub struct DeserializeSeed<D> {
state: Option<D>,
}
impl<'de, D: de::DeserializeSeed<'de>> super::DeserializeSeed<'de> for DeserializeSeed<D> {
type Value = D::Value;
fn erased_deserialize(
&mut self,
deserializer: &mut dyn erased_serde::Deserializer<'de>,
) -> erased_serde::Result<Self::Value> {
de::DeserializeSeed::deserialize(self.state.take().unwrap(), deserializer)
.map_err(de::Error::custom)
}
}
}
impl<'de, T> de::DeserializeSeed<'de> for &mut dyn DeserializeSeed<'de, Value = T> {
type Value = T;
fn deserialize<D: de::Deserializer<'de>>(self, deserializer: D) -> Result<T, D::Error> {
let mut erased = <dyn erased_serde::Deserializer>::erase(deserializer);
self.erased_deserialize(&mut erased)
.map_err(de::Error::custom)
}
}
}
pub mod response {
use core::future::Future;
use core::marker::Unpin;
use core::pin::Pin;
use core::task::{Context, Poll};
use serde::de;
pub struct ResponseFuture<T> {
seed: Option<T>,
}
impl<T: for<'de> de::DeserializeSeed<'de> + Unpin> ResponseFuture<T> {
pub fn new(seed: T) -> Self {
Self { seed: Some(seed) }
}
}
impl<T: for<'de> de::DeserializeSeed<'de> + Unpin> Future for ResponseFuture<T> {
type Output = Result<<T as de::DeserializeSeed<'static>>::Value, serde_json::Error>;
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
let body = "null";
let mut deserializer = serde_json::Deserializer::from_str(body);
let response = self.seed.take().unwrap().deserialize(&mut deserializer)?;
Poll::Ready(Ok(response))
}
}
}
#[cfg(test)]
mod tests {
use serde::de;
use crate::erased;
use crate::response::ResponseFuture;
struct DeserializeSeedImpl;
impl<'de> de::DeserializeSeed<'de> for DeserializeSeedImpl {
type Value = ();
fn deserialize<D: de::Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
<de::IgnoredAny as de::Deserialize>::deserialize(d).map(|_| {})
}
}
fn it_works() {
let mut seed = erased::erase_seed(DeserializeSeedImpl);
let response: ResponseFuture<&mut dyn erased::DeserializeSeed<Value = ()>> =
ResponseFuture::new(&mut seed);
//~^ ERROR implementation of `serde::de::DeserializeSeed` is not general enough
let _ = async move {
response.await.unwrap()
//~^ ERROR implementation of `serde::de::DeserializeSeed` is not general enough
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment