Created
October 31, 2015 17:58
-
-
Save apoelstra/3a84aff269e126df19bf to your computer and use it in GitHub Desktop.
This file contains 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
// 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