Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ExpHP
Last active March 1, 2020 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ExpHP/3142aa4e2d7aa9d11f2f3c87f3066915 to your computer and use it in GitHub Desktop.
Save ExpHP/3142aa4e2d7aa9d11f2f3c87f3066915 to your computer and use it in GitHub Desktop.
erased deserialize
use std::marker::PhantomData;
use std::any::Any;
use erased_serde::{Error, Deserializer};
use serde_json::json;
/// Dummy type that concretely represents "an impl of Deserialize".
///
/// If you want to deserialize arbitrary types, you'll have to create a
/// `DeserializeImpl<T>` in a portion of code that knows which type needs to
/// be deserialized, and then unsize it to `dyn DeserializeOwned` to be handed
/// off to object-safe code.
pub struct DeserializeImpl<T> {
_marker: PhantomData<T>,
}
impl<T: serde::de::DeserializeOwned> DeserializeImpl<T> {
pub fn new() -> Self { DeserializeImpl { _marker: PhantomData } }
}
pub trait DeserializeOwned {
fn erased_deserialize(&self, deserializer: &mut dyn Deserializer) -> Result<Box<dyn Any>, Error>;
}
impl<T: serde::de::DeserializeOwned + 'static> DeserializeOwned for DeserializeImpl<T> {
fn erased_deserialize(&self, deserializer: &mut dyn Deserializer) -> Result<Box<dyn Any>, Error> {
T::deserialize(deserializer)
.map(|value| Box::new(value) as Box<dyn Any>)
.map_err(serde::de::Error::custom)
}
}
fn main() {
use std::collections::BTreeMap as Map;
// The values in this map are boxed trait objects, which is not possible
// with the normal serde::DeserializeOwned because of object safety.
let mut types: Map<&str, Box<dyn DeserializeOwned>> = Map::new();
types.insert("u8", Box::new(DeserializeImpl::<Vec<u8>>::new()));
types.insert("u32", Box::new(DeserializeImpl::<Vec<u32>>::new()));
// Parse the same JSON as each of these two different types.
let outputs = types.into_iter()
.map(|(key, dummy)| {
let deserializer = &mut Deserializer::erase(json!([10, 20, 40])) as &mut dyn Deserializer;
let output = dummy.erased_deserialize(deserializer).unwrap(); // look ma no static types
(key, output)
}).collect::<Map<&str, _>>();
println!("{:?}", outputs["u8"].downcast_ref::<Vec<u8>>().unwrap());
println!("{:?}", outputs["u32"].downcast_ref::<Vec<u32>>().unwrap());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment