Skip to content

Instantly share code, notes, and snippets.

@erickt
Forked from shahn/gist:32fa57a6fd1f2e3b3224b3e925308960
Last active April 3, 2016 19:07
Show Gist options
  • Save erickt/ec0c196dd3790ce1ee1cb16ca8faaa85 to your computer and use it in GitHub Desktop.
Save erickt/ec0c196dd3790ce1ee1cb16ca8faaa85 to your computer and use it in GitHub Desktop.
#![feature(plugin, custom_derive)]
#![plugin(serde_macros)]
extern crate serde;
extern crate serde_json;
use std::error::Error;
use serde::de::Error as SerdeError;
use serde_json::Value;
pub enum Foo {
Stuff(Stuff),
OtherStuff(OtherStuff),
}
#[derive(Deserialize)]
pub struct Stuff {
pub stuff: u32,
}
#[derive(Deserialize)]
pub struct OtherStuff {
pub stuff: u32,
}
macro_rules! try_conv {
($expr:expr) => (match $expr {
Ok(val) => val,
Err(err) => {
use std::error::Error;
return Err(D::Error::custom(err.description()))
}
})
}
impl serde::Deserialize for Foo {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: serde::Deserializer
{
let value: Value = try!(Value::deserialize(deserializer));
enum ClassType {
Stuff,
OtherStuff,
}
// XXX find a solution to get rid of this clone
let kind = match value.find("classtype") {
Some(&Value::String(ref s)) => {
match &**s {
"stuff" => { ClassType::Stuff }
"otherstuff" => { ClassType::OtherStuff }
_ => {
return Err(D::Error::custom("invalid"));
}
}
}
Some(_) => {
return Err(D::Error::custom("non-string 'classtype'"))
}
None => {
return Err(D::Error::missing_field("classtype"));
}
};
match kind {
ClassType::Stuff => {
let stuff: Stuff = try_conv!(serde_json::from_value(value));
Ok(Foo::Stuff(stuff))
}
ClassType::OtherStuff => {
let other_stuff: OtherStuff = try_conv!(serde_json::from_value(value));
Ok(Foo::OtherStuff(other_stuff))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment