extern crate serde;
extern crate serde_json;
extern crate serde_tagged;
extern crate erased_serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate downcast_rs;
use std::collections::BTreeMap;
use serde_tagged::de::BoxFnSeed;
use serde_tagged::util::erased::SerializeErased;
use downcast_rs::Downcast;
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct A {
foo: String,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum B {
Str(String),
Int(i64),
}
pub trait TypeId {
fn type_id(&self) -> &'static str;
}
impl TypeId for A {
fn type_id(&self) -> &'static str {
"A"
}
}
impl TypeId for B {
fn type_id(&self) -> &'static str {
"B"
}
}
pub trait Stored: erased_serde::Serialize + TypeId + std::fmt::Debug + Downcast {}
impl<T> Stored for T where T: erased_serde::Serialize + TypeId + std::fmt::Debug + Downcast {}
impl_downcast!(Stored);
impl<'a> serde::Serialize for dyn Stored + 'a {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_tagged::ser::external::serialize(
serializer,
TypeId::type_id(self),
&SerializeErased(self),
)
}
}
impl<'de> serde::Deserialize<'de> for Box<dyn Stored> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
serde_tagged::de::external::deserialize(deserializer, get_registry())
}
}
pub type TypeRegistry = BTreeMap<&'static str, BoxFnSeed<Box<dyn Stored>>>;
pub fn get_registry() -> &'static TypeRegistry {
lazy_static! {
static ref REG: TypeRegistry = {
let mut reg = TypeRegistry::new();
reg.insert("A", BoxFnSeed::new(deserialize_erased::a));
reg.insert("B", BoxFnSeed::new(deserialize_erased::b));
reg
};
}
®
}
mod deserialize_erased {
use super::*;
use erased_serde::{Deserializer, Error};
use serde::Deserialize;
pub fn a<'de>(de: &mut dyn Deserializer<'de>) -> Result<Box<dyn Stored>, Error> {
Ok(Box::new(A::deserialize(de)?))
}
pub fn b<'de>(de: &mut dyn Deserializer<'de>) -> Result<Box<dyn Stored>, Error> {
Ok(Box::new(B::deserialize(de)?))
}
}
fn main() {
let a = Box::new(A {
foo: "bar".to_owned(),
});
let b = Box::new(B::Str("Hello World".to_owned()));
let c = Box::new(B::Int(42));
let ser_a: Box<dyn Stored> = a.clone();
let ser_b: Box<dyn Stored> = b.clone();
let ser_c: Box<dyn Stored> = c.clone();
let ser_a = serde_json::to_string_pretty(&ser_a).unwrap();
let ser_b = serde_json::to_string_pretty(&ser_b).unwrap();
let ser_c = serde_json::to_string_pretty(&ser_c).unwrap();
assert_json_equal(
&ser_a,
r###"
{
"A": {
"foo": "bar"
}
}
"###,
);
assert_json_equal(
&ser_b,
r###"
{
"B": {
"Str": "Hello World"
}
}
"###,
);
assert_json_equal(
&ser_c,
r###"
{
"B": {
"Int": 42
}
}
"###,
);
let de_a: Box<dyn Stored> = serde_json::from_str(&ser_a).unwrap();
let de_b: Box<dyn Stored> = serde_json::from_str(&ser_b).unwrap();
let de_c: Box<dyn Stored> = serde_json::from_str(&ser_c).unwrap();
let ref_a: &A = de_a.downcast_ref().unwrap();
let ref_b: &B = de_b.downcast_ref().unwrap();
let ref_c: &B = de_c.downcast_ref().unwrap();
assert_eq!(&*a, ref_a);
assert_eq!(&*b, ref_b);
assert_eq!(&*c, ref_c);
}
fn assert_json_equal(a: &str, b: &str) {
let a: serde_json::Value = serde_json::from_str(a).unwrap();
let b: serde_json::Value = serde_json::from_str(b).unwrap();
assert_eq!(a, b);
}