Ask proc_macro_derive to ignore serde attributes

This commit is contained in:
David Tolnay
2016-11-15 21:29:34 -05:00
parent 133d117bf4
commit a16f07858b
4 changed files with 22 additions and 88 deletions
+18 -73
View File
@@ -27,9 +27,6 @@ extern crate syn;
#[macro_use]
extern crate quote;
#[cfg(feature = "with-syn")]
extern crate post_expansion;
#[cfg(feature = "with-syntex")]
use std::path::Path;
@@ -73,8 +70,8 @@ fn syntex_registry() -> syntex::Registry {
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Serialize", expand_derive_serialize);
reg.add_decorator("derive_Deserialize", expand_derive_deserialize);
reg.add_decorator("derive_Serialize", shim::expand_derive_serialize);
reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize);
reg.add_post_expansion_pass(strip_attributes);
@@ -112,19 +109,19 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
reg.register_syntax_extension(
syntax::parse::token::intern("derive_Serialize"),
syntax::ext::base::MultiDecorator(
Box::new(expand_derive_serialize)));
Box::new(shim::expand_derive_serialize)));
reg.register_syntax_extension(
syntax::parse::token::intern("derive_Deserialize"),
syntax::ext::base::MultiDecorator(
Box::new(expand_derive_deserialize)));
Box::new(shim::expand_derive_deserialize)));
reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
macro_rules! shim {
($name:ident $pkg:ident :: $func:ident) => {
fn $func(
pub fn $func(
cx: &mut ::syntax::ext::base::ExtCtxt,
span: ::syntax::codemap::Span,
meta_item: &::syntax::ast::MetaItem,
@@ -160,6 +157,7 @@ macro_rules! shim {
use syntax::print::pprust;
let s = pprust::item_to_string(item);
use {syn, $pkg};
let syn_item = syn::parse_macro_input(&s).unwrap();
let expanded = match $pkg::$func(&syn_item) {
Ok(expanded) => expanded.to_string(),
@@ -178,72 +176,19 @@ macro_rules! shim {
};
}
shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);
mod shim {
shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);
}
#[cfg(feature = "with-syn")]
pub fn expand_single_item(item: &str) -> Result<String, String> {
pub fn expand_derive_serialize(item: &str) -> Result<String, String> {
let syn_item = syn::parse_macro_input(item).unwrap();
let (ser, de, syn_item) = strip_serde_derives(syn_item);
let expanded_ser = if ser {
Some(try!(ser::expand_derive_serialize(&syn_item)))
} else {
None
};
let expanded_de = if de {
Some(try!(de::expand_derive_deserialize(&syn_item)))
} else {
None
};
let syn_item = post_expansion::strip_attrs_later(syn_item, &["serde"], "serde");
return Ok(quote!(#expanded_ser #expanded_de #syn_item).to_string());
fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
let mut ser = false;
let mut de = false;
let item = syn::MacroInput {
attrs: item.attrs.into_iter().flat_map(|attr| {
if attr.is_sugared_doc || attr.style != syn::AttrStyle::Outer {
return Some(attr);
}
let (name, nested) = match attr.value {
syn::MetaItem::List(name, nested) => (name, nested),
_ => return Some(attr)
};
if name != "derive" {
return Some(syn::Attribute {
style: syn::AttrStyle::Outer,
value: syn::MetaItem::List(name, nested),
is_sugared_doc: false,
});
}
let rest: Vec<_> = nested.into_iter().filter(|nested| {
use syn::MetaItem::Word;
use syn::NestedMetaItem::MetaItem;
match *nested {
MetaItem(Word(ref word)) if word == "Serialize" => {
ser = true;
false
}
MetaItem(Word(ref word)) if word == "Deserialize" => {
de = true;
false
}
_ => true,
}
}).collect();
if rest.is_empty() {
None
} else {
Some(syn::Attribute {
style: syn::AttrStyle::Outer,
value: syn::MetaItem::List(name, rest),
is_sugared_doc: false,
})
}
}).collect(),
..item
};
(ser, de, item)
}
ser::expand_derive_serialize(&syn_item).map(|derive| derive.to_string())
}
#[cfg(feature = "with-syn")]
pub fn expand_derive_deserialize(item: &str) -> Result<String, String> {
let syn_item = syn::parse_macro_input(item).unwrap();
de::expand_derive_deserialize(&syn_item).map(|derive| derive.to_string())
}