Last active
March 1, 2020 08:05
-
-
Save ExpHP/3142aa4e2d7aa9d11f2f3c87f3066915 to your computer and use it in GitHub Desktop.
erased deserialize
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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