Compare commits

...

8 Commits

Author SHA1 Message Date
David Tolnay 17fb4cb503 Release 0.8.18 2016-11-19 11:40:00 -08:00
David Tolnay 5bd0386b8e Merge pull request #618 from serde-rs/up
Ask proc_macro_derive to ignore serde attributes
2016-11-19 14:19:15 -05:00
David Tolnay 8b484c9703 Hide the serde_codegen functions from docs 2016-11-15 21:37:19 -05:00
David Tolnay a16f07858b Ask proc_macro_derive to ignore serde attributes 2016-11-15 21:29:34 -05:00
David Tolnay 133d117bf4 Bump post-expansion dependency 2016-11-07 11:16:14 -08:00
David Tolnay e7f3a80867 Update serde codegen to syn 0.10 2016-11-02 22:58:55 -07:00
David Tolnay f8c3d225a3 Shorten the syn meta item matches 2016-11-02 22:56:27 -07:00
David Tolnay 6d40d9e8ec Update codegen internals to syn 0.10 2016-11-02 22:52:20 -07:00
9 changed files with 83 additions and 129 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "0.8.17"
version = "0.8.18"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
+5 -6
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_codegen"
version = "0.8.17"
version = "0.8.18"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework"
@@ -22,9 +22,8 @@ with-syn = []
[dependencies]
clippy = { version = "^0.*", optional = true }
post-expansion = "0.1.0"
quote = "0.3"
serde_codegen_internals = { version = "=0.10.0", default-features = false, path = "../serde_codegen_internals" }
syn = { version = "0.9", features = ["aster", "visit"] }
syntex = { version = "^0.48.0", optional = true }
syntex_syntax = { version = "^0.48.0", optional = true }
serde_codegen_internals = { version = "=0.11.0", default-features = false, path = "../serde_codegen_internals" }
syn = { version = "0.10", features = ["aster", "visit"] }
syntex = { version = "^0.50.0", optional = true }
syntex_syntax = { version = "^0.50.0", optional = true }
+22 -71
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,70 +176,23 @@ 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> {
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
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| {
match *nested {
syn::MetaItem::Word(ref word) if word == "Serialize" => {
ser = true;
false
}
syn::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")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
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())
}
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_codegen_internals"
version = "0.10.0"
version = "0.11.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde codegen. Unstable."
@@ -15,4 +15,4 @@ unstable-testing = ["clippy"]
[dependencies]
clippy = { version = "^0.*", optional = true }
syn = "0.9"
syn = "0.10"
+42 -28
View File
@@ -1,5 +1,7 @@
use Ctxt;
use syn;
use syn::MetaItem::{List, NameValue, Word};
use syn::NestedMetaItem::{Literal, MetaItem};
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Item::from_ast`, `attr::Variant::from_ast`, and
@@ -105,7 +107,7 @@ impl Item {
for meta_item in meta_items {
match meta_item {
// Parse `#[serde(rename="foo")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "rename" => {
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone());
de_name.set(s);
@@ -113,7 +115,7 @@ impl Item {
}
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
syn::MetaItem::List(ref name, ref meta_items) if name == "rename" => {
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser);
de_name.set_opt(de);
@@ -121,12 +123,12 @@ impl Item {
}
// Parse `#[serde(deny_unknown_fields)]`
syn::MetaItem::Word(ref name) if name == "deny_unknown_fields" => {
MetaItem(Word(ref name)) if name == "deny_unknown_fields" => {
deny_unknown_fields.set_true();
}
// Parse `#[serde(bound="D: Serialize")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "bound" => {
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
@@ -134,17 +136,21 @@ impl Item {
}
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
syn::MetaItem::List(ref name, ref meta_items) if name == "bound" => {
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
}
}
_ => {
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde container attribute `{}`",
meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde container attribute"));
}
}
}
}
@@ -192,7 +198,7 @@ impl Variant {
for meta_item in meta_items {
match meta_item {
// Parse `#[serde(rename="foo")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "rename" => {
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone());
de_name.set(s);
@@ -200,17 +206,21 @@ impl Variant {
}
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
syn::MetaItem::List(ref name, ref meta_items) if name == "rename" => {
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser);
de_name.set_opt(de);
}
}
_ => {
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`",
meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde variant attribute"));
}
}
}
}
@@ -278,7 +288,7 @@ impl Field {
for meta_item in meta_items {
match meta_item {
// Parse `#[serde(rename="foo")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "rename" => {
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone());
de_name.set(s);
@@ -286,7 +296,7 @@ impl Field {
}
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
syn::MetaItem::List(ref name, ref meta_items) if name == "rename" => {
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser);
de_name.set_opt(de);
@@ -294,50 +304,50 @@ impl Field {
}
// Parse `#[serde(default)]`
syn::MetaItem::Word(ref name) if name == "default" => {
MetaItem(Word(ref name)) if name == "default" => {
default.set(FieldDefault::Default);
}
// Parse `#[serde(default="...")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "default" => {
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
default.set(FieldDefault::Path(path));
}
}
// Parse `#[serde(skip_serializing)]`
syn::MetaItem::Word(ref name) if name == "skip_serializing" => {
MetaItem(Word(ref name)) if name == "skip_serializing" => {
skip_serializing.set_true();
}
// Parse `#[serde(skip_deserializing)]`
syn::MetaItem::Word(ref name) if name == "skip_deserializing" => {
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
skip_deserializing.set_true();
}
// Parse `#[serde(skip_serializing_if="...")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "skip_serializing_if" => {
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
skip_serializing_if.set(path);
}
}
// Parse `#[serde(serialize_with="...")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "serialize_with" => {
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
serialize_with.set(path);
}
}
// Parse `#[serde(deserialize_with="...")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "deserialize_with" => {
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
deserialize_with.set(path);
}
}
// Parse `#[serde(bound="D: Serialize")]`
syn::MetaItem::NameValue(ref name, ref lit) if name == "bound" => {
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
@@ -345,17 +355,21 @@ impl Field {
}
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
syn::MetaItem::List(ref name, ref meta_items) if name == "bound" => {
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
}
}
_ => {
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde field attribute `{}`",
meta_item.name()));
}
Literal(_) => {
cx.error(format!("unexpected literal in serde field attribute"));
}
}
}
}
@@ -424,7 +438,7 @@ type SerAndDe<T> = (Option<T>, Option<T>);
fn get_ser_and_de<T, F>(
cx: &Ctxt,
attr_name: &'static str,
items: &[syn::MetaItem],
items: &[syn::NestedMetaItem],
f: F
) -> Result<SerAndDe<T>, ()>
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>,
@@ -434,13 +448,13 @@ fn get_ser_and_de<T, F>(
for item in items {
match *item {
syn::MetaItem::NameValue(ref name, ref lit) if name == "serialize" => {
MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => {
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
ser_item.set(v);
}
}
syn::MetaItem::NameValue(ref name, ref lit) if name == "deserialize" => {
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => {
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
de_item.set(v);
}
@@ -459,21 +473,21 @@ fn get_ser_and_de<T, F>(
fn get_renames(
cx: &Ctxt,
items: &[syn::MetaItem],
items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<String>, ()> {
get_ser_and_de(cx, "rename", items, get_string_from_lit)
}
fn get_where_predicates(
cx: &Ctxt,
items: &[syn::MetaItem],
items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
}
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::MetaItem>> {
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMetaItem>> {
match attr.value {
syn::MetaItem::List(ref name, ref items) if name == "serde" => {
List(ref name, ref items) if name == "serde" => {
Some(items.iter().cloned().collect())
}
_ => None
+4 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "0.8.17"
version = "0.8.18"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -14,11 +14,8 @@ include = ["Cargo.toml", "src/**/*.rs"]
name = "serde_derive"
proc-macro = true
[dependencies]
post-expansion = "0.1.0"
[dependencies.serde_codegen]
version = "=0.8.17"
version = "=0.8.18"
path = "../serde_codegen"
default-features = false
features = ["with-syn"]
@@ -26,5 +23,5 @@ features = ["with-syn"]
[dev-dependencies]
compiletest_rs = "^0.2.0"
fnv = "1.0"
serde = { version = "0.8.17", path = "../serde" }
serde_test = { version = "0.8.17", path = "../serde_test" }
serde = { version = "0.8.18", path = "../serde" }
serde_test = { version = "0.8.18", path = "../serde_test" }
+4 -11
View File
@@ -4,27 +4,20 @@
extern crate proc_macro;
extern crate serde_codegen;
#[macro_use]
extern crate post_expansion;
use proc_macro::TokenStream;
#[proc_macro_derive(Serialize)]
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Serialize)]\n{}", input);
match serde_codegen::expand_single_item(&item) {
match serde_codegen::expand_derive_serialize(&input.to_string()) {
Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
}
#[proc_macro_derive(Deserialize)]
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Deserialize)]\n{}", input);
match serde_codegen::expand_single_item(&item) {
match serde_codegen::expand_derive_deserialize(&input.to_string()) {
Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
}
register_post_expansion!(PostExpansion_serde);
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "0.8.17"
version = "0.8.18"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
@@ -12,4 +12,4 @@ keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[dependencies]
serde = { version = "0.8.17", path = "../serde" }
serde = { version = "0.8.18", path = "../serde" }
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_testing"
version = "0.8.17"
version = "0.8.18"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"