dtolnay / erased-serde

Type-erased Serialize, Serializer and Deserializer traits
Apache License 2.0
709 stars 36 forks source link

How to deserialize erased object in place #33

Closed dtolnay closed 4 years ago

dtolnay commented 4 years ago

Moved from @rasky's question in https://github.com/dtolnay/erased-serde/issues/25#issuecomment-449651549:

I already have an object in memory of the correct type, behind a trait object, and I would like to invoke deserialize_in_place on it, using some type erasure magic to make it work through the trait object. Is that possible? Any hint on how to implement it?

dtolnay commented 4 years ago

Yes, here is an example. The erased_deserialize_in_place at the bottom deserializes into a trait object out without knowing the concrete type of the deserialized value.

use erased_serde::Result;

pub trait ErasedDeserialize<'de> {
    fn erased_deserialize_in_place(
        &mut self,
        de: &mut dyn erased_serde::Deserializer<'de>,
    ) -> Result<()>;
}

impl<'de, T> ErasedDeserialize<'de> for T
where
    T: serde::Deserialize<'de>,
{
    fn erased_deserialize_in_place(
        &mut self,
        de: &mut dyn erased_serde::Deserializer<'de>,
    ) -> Result<()> {
        serde::Deserialize::deserialize_in_place(de, self)
    }
}

////////////////////////////////////////////////////////////////////////////////

fn erased_deserialize_in_place<'de>(
    out: &mut dyn ErasedDeserialize<'de>,
    json: &'de str,
) -> Result<()> {
    let mut de = serde_json::Deserializer::from_str(json);
    let mut erased = erased_serde::Deserializer::erase(&mut de);
    out.erased_deserialize_in_place(&mut erased)
}

fn main() {
    let mut value = Vec::<String>::new();
    let j = r#" ["x","y","z"] "#;
    erased_deserialize_in_place(&mut value, j).unwrap();
    println!("deserialized = {:#?}", value);
}