Skip to content

Instantly share code, notes, and snippets.

@apoelstra
Created October 31, 2015 17:58
Show Gist options
  • Save apoelstra/3a84aff269e126df19bf to your computer and use it in GitHub Desktop.
Save apoelstra/3a84aff269e126df19bf to your computer and use it in GitHub Desktop.
// Rust JSON-RPC Library
// Written in 2015 by
// Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//! # Macros
//!
//! Macros to replace serde's codegen while that is not stable
//!
#[macro_export]
macro_rules! serde_struct_enum_impl {
($name:ident, $modname:ident,
$($varname:ident, $structname:ident, $($fe:ident $(<- $alt:expr)*),*);*
) => (
mod $modname {
#[allow(non_camel_case_types)]
$(enum $varname { $($fe),* })*
enum Enum { $($varname($varname)),* }
struct EnumVisitor;
impl ::serde::de::Visitor for EnumVisitor {
type Value = Enum;
fn visit_str<E>(&mut self, value: &str) -> Result<Enum, E>
where E: ::serde::de::Error
{
match value {
$($(
stringify!($fe) $(| $alt)* => Ok(Enum::$varname($varname::$fe))
),*),*,
_ => Err(::serde::de::Error::syntax("unexpected field")),
}
}
}
impl ::serde::Deserialize for Enum {
fn deserialize<D>(deserializer: &mut D) -> Result<Enum, D::Error>
where D: ::serde::de::Deserializer
{
deserializer.visit(EnumVisitor)
}
}
pub struct Visitor;
impl ::serde::de::Visitor for Visitor {
type Value = super::$name;
fn visit_map<V>(&mut self, mut v: V) -> Result<super::$name, V::Error>
where V: ::serde::de::MapVisitor
{
$($(let mut $fe = None;)*)*
loop {
match try!(v.visit_key()) {
$($(Some(Enum::$varname($varname::$fe)) => {
$fe = Some(try!(v.visit_value())); })*)*
None => { break; }
}
}
// try to find a variant for which we have all fields
$(
let mut $structname = true;
$(if $fe.is_none() { $structname = false })*
// if we found one, success. extra fields is not an error,
// it'd be too much of a PITA to manage overlapping field
// sets otherwise.
if $structname {
$(let $fe = $fe.unwrap();)*
try!(v.end());
return Ok(super::$name::$varname(super::$structname { $($fe: $fe),* }))
}
)*
// If we get here we failed
Err(::serde::de::Error::syntax("did not get all fields"))
}
}
}
impl ::serde::Deserialize for $name {
fn deserialize<D>(deserializer: &mut D) -> Result<$name, D::Error>
where D: serde::de::Deserializer
{
static FIELDS: &'static [&'static str] = &[$($(stringify!($fe)),*),*];
deserializer.visit_struct(stringify!($name), FIELDS, $modname::Visitor)
}
}
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment