Compare commits

...

35 Commits

Author SHA1 Message Date
David Tolnay 9338c4f1b9 Release 0.8.21 2016-12-24 13:10:24 -05:00
David Tolnay 28d67f4172 Format variant-skip message only if variant is skipped 2016-12-24 13:10:06 -05:00
David Tolnay 2401ae61a8 Update to syntex 0.52 2016-12-24 12:42:23 -05:00
David Tolnay 57d3fce0c6 Further simplify variant serialization patterns 2016-12-24 12:28:46 -05:00
David Tolnay a020cceed8 Simplify variant serialize patterns 2016-12-24 12:22:45 -05:00
David Tolnay 49e985eb90 Update message for skipped enum variant 2016-12-24 12:16:28 -05:00
David Tolnay 63def96c66 Merge pull request #653 from shinglyu/skip_se
Implement skip_serializing for enum variant
2016-12-24 11:40:21 -05:00
Shing Lyu 2fea8c9c28 Implement skip_serializing for enum variant 2016-12-24 22:34:22 +08:00
David Tolnay 2c984980a0 Link to release notes from readme 2016-12-22 21:52:37 -05:00
David Tolnay 36f07912b8 Remove no-longer-necessary cfg
This was fixed in Rust, allowing proc macro crates to be tested.
2016-12-17 17:32:11 -08:00
David Tolnay 7222cf7514 Ignore warning from unused enum variant 2016-12-17 17:31:11 -08:00
David Tolnay 08c59a2e0e Release 0.8.20 2016-12-16 07:58:52 -08:00
David Tolnay 4a0bf4de65 Merge pull request #641 from shinglyu/deser_enum
Implemented skip_deserializing for enum
2016-12-16 07:53:34 -08:00
Shing Lyu 95ffca9bbe Implemented skip_deserializing for enum 2016-12-16 20:29:21 +08:00
David Tolnay 5e47c87ba0 Add test for deserializing unit to string 2016-12-01 04:46:29 -08:00
David Tolnay c6d5d9be14 Merge pull request #635 from serde-rs/oli-obk-patch-1
Enable deserializing an empty `String` from a unit value
2016-12-01 07:46:07 -05:00
Oliver Schneider d63d09f4db Enable deserializing an empty String from a unit value 2016-12-01 11:23:12 +01:00
David Tolnay de6d00c306 Merge pull request #628 from serde-rs/str
Do not copy tokens to String after expanding
2016-11-24 17:33:19 -05:00
David Tolnay 5bda95ba81 Do not copy tokens to String after expanding 2016-11-24 13:07:47 -08:00
David Tolnay 36641e7b81 Release 0.8.19 2016-11-23 09:14:03 -08:00
David Tolnay 6eca34c45c Drop libsyntax 2016-11-23 09:13:21 -08:00
David Tolnay 7efa0153b0 Drop testing on rust 1.10 2016-11-19 15:24:40 -08:00
David Tolnay 8dba87661b Bump serde_codegen_internals because it failed to publish somehow 2016-11-19 11:47:19 -08:00
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
David Tolnay c91fca19e1 Release 0.8.17 2016-11-02 09:26:04 -07:00
David Tolnay f13a805530 Merge pull request #605 from serde-rs/up
Bump syntex to 0.48
2016-11-02 09:24:55 -07:00
David Tolnay 54802983b8 Bump syntex to 0.48 2016-11-02 09:12:22 -07:00
David Tolnay f430d9d1c8 Remove unneeded type ascription 2016-10-23 21:06:50 -07:00
16 changed files with 235 additions and 235 deletions
+1 -1
View File
@@ -1,8 +1,8 @@
sudo: false sudo: false
language: rust language: rust
rust: rust:
- 1.10.0
- 1.11.0 - 1.11.0
- 1.12.0
- stable - stable
- beta - beta
- nightly - nightly
+1
View File
@@ -11,6 +11,7 @@ You may be looking for:
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html) - [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
- [Examples](https://serde.rs/examples.html) - [Examples](https://serde.rs/examples.html)
- [API documentation](https://docs.serde.rs/serde/) - [API documentation](https://docs.serde.rs/serde/)
- [Release notes](https://github.com/serde-rs/serde/releases)
## Serde in action ## Serde in action
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "0.8.16" version = "0.8.21"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
+6
View File
@@ -283,6 +283,12 @@ impl Visitor for StringVisitor {
Ok(v) Ok(v)
} }
fn visit_unit<E>(&mut self) -> Result<String, E>
where E: Error,
{
Ok(String::new())
}
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<String, E> fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<String, E>
where E: Error, where E: Error,
{ {
+6 -7
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen" name = "serde_codegen"
version = "0.8.16" version = "0.8.21"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" description = "Macros to auto-generate implementations for the serde framework"
@@ -22,9 +22,8 @@ with-syn = []
[dependencies] [dependencies]
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
post-expansion = "0.1.0" quote = "0.3.8"
quote = "0.3" serde_codegen_internals = { version = "=0.11.3", default-features = false, path = "../serde_codegen_internals" }
serde_codegen_internals = { version = "=0.10.0", default-features = false, path = "../serde_codegen_internals" } syn = { version = "0.10", features = ["aster", "visit"] }
syn = { version = "0.9", features = ["aster", "visit"] } syntex = { version = "^0.52.0", optional = true }
syntex = { version = "^0.46.0", optional = true } syntex_syntax = { version = "^0.52.0", optional = true }
syntex_syntax = { version = "^0.46.0", optional = true }
+2 -1
View File
@@ -496,6 +496,7 @@ fn deserialize_item_enum(
let variant_visitor = deserialize_field_visitor( let variant_visitor = deserialize_field_visitor(
variants.iter() variants.iter()
.filter(|variant| !variant.attrs.skip_deserializing())
.map(|variant| variant.attrs.name().deserialize_name()) .map(|variant| variant.attrs.name().deserialize_name())
.collect(), .collect(),
item_attrs, item_attrs,
@@ -518,7 +519,7 @@ fn deserialize_item_enum(
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
let mut variant_arms = vec![]; let mut variant_arms = vec![];
for (i, variant) in variants.iter().enumerate() { for (i, variant) in variants.iter().filter(|variant| !variant.attrs.skip_deserializing()).enumerate() {
let variant_name = aster::id(format!("__field{}", i)); let variant_name = aster::id(format!("__field{}", i));
let variant_name = quote!(__Field::#variant_name); let variant_name = quote!(__Field::#variant_name);
+28 -104
View File
@@ -2,7 +2,6 @@
#![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))] #![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))] #![cfg_attr(feature = "clippy", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
// The `quote!` macro requires deep recursion. // The `quote!` macro requires deep recursion.
#![recursion_limit = "192"] #![recursion_limit = "192"]
@@ -16,26 +15,13 @@ extern crate syntex;
#[macro_use] #[macro_use]
extern crate syntex_syntax as syntax; extern crate syntex_syntax as syntax;
#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;
#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;
extern crate syn; extern crate syn;
#[macro_use] #[macro_use]
extern crate quote; extern crate quote;
#[cfg(feature = "with-syn")]
extern crate post_expansion;
#[cfg(feature = "with-syntex")] #[cfg(feature = "with-syntex")]
use std::path::Path; use std::path::Path;
#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;
mod bound; mod bound;
mod de; mod de;
mod ser; mod ser;
@@ -52,11 +38,11 @@ fn syntex_registry() -> syntex::Registry {
impl fold::Folder for StripAttributeFolder { impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> { fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node { if attr.value.name == "serde" {
ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; } if let ast::MetaItemKind::List(..) = attr.value.node {
_ => {} return None;
}
} }
Some(attr) Some(attr)
} }
@@ -73,8 +59,8 @@ fn syntex_registry() -> syntex::Registry {
reg.add_attr("feature(custom_derive)"); reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)"); reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Serialize", expand_derive_serialize); reg.add_decorator("derive_Serialize", shim::expand_derive_serialize);
reg.add_decorator("derive_Deserialize", expand_derive_deserialize); reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize);
reg.add_post_expansion_pass(strip_attributes); reg.add_post_expansion_pass(strip_attributes);
@@ -107,24 +93,9 @@ pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
syntex::with_extra_stack(expand_thread) syntex::with_extra_stack(expand_thread)
} }
#[cfg(not(feature = "with-syntex"))]
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)));
reg.register_syntax_extension(
syntax::parse::token::intern("derive_Deserialize"),
syntax::ext::base::MultiDecorator(
Box::new(expand_derive_deserialize)));
reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
macro_rules! shim { macro_rules! shim {
($name:ident $pkg:ident :: $func:ident) => { ($name:ident $pkg:ident :: $func:ident) => {
fn $func( pub fn $func(
cx: &mut ::syntax::ext::base::ExtCtxt, cx: &mut ::syntax::ext::base::ExtCtxt,
span: ::syntax::codemap::Span, span: ::syntax::codemap::Span,
meta_item: &::syntax::ast::MetaItem, meta_item: &::syntax::ast::MetaItem,
@@ -147,11 +118,10 @@ macro_rules! shim {
struct MarkSerdeAttributesUsed; struct MarkSerdeAttributesUsed;
impl visit::Visitor for MarkSerdeAttributesUsed { impl visit::Visitor for MarkSerdeAttributesUsed {
fn visit_attribute(&mut self, attr: &ast::Attribute) { fn visit_attribute(&mut self, attr: &ast::Attribute) {
match attr.node.value.node { if attr.value.name == "serde" {
ast::MetaItemKind::List(ref name, _) if name == "serde" => { if let ast::MetaItemKind::List(..) = attr.value.node {
attr::mark_used(attr); attr::mark_used(attr);
} }
_ => {}
} }
} }
} }
@@ -160,6 +130,7 @@ macro_rules! shim {
use syntax::print::pprust; use syntax::print::pprust;
let s = pprust::item_to_string(item); let s = pprust::item_to_string(item);
use {syn, $pkg};
let syn_item = syn::parse_macro_input(&s).unwrap(); let syn_item = syn::parse_macro_input(&s).unwrap();
let expanded = match $pkg::$func(&syn_item) { let expanded = match $pkg::$func(&syn_item) {
Ok(expanded) => expanded.to_string(), Ok(expanded) => expanded.to_string(),
@@ -171,78 +142,31 @@ macro_rules! shim {
use syntax::parse; use syntax::parse;
let name = stringify!($name).to_string(); let name = stringify!($name).to_string();
let cfg = Vec::new();
let sess = cx.parse_sess; let sess = cx.parse_sess;
let impl_item = parse::parse_item_from_source_str(name, expanded, cfg, sess); let impl_item = parse::parse_item_from_source_str(name, expanded, sess);
push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap())); push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
} }
}; };
} }
shim!(Serialize ser::expand_derive_serialize); #[cfg(feature = "with-syntex")]
shim!(Deserialize de::expand_derive_deserialize); mod shim {
shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);
}
#[cfg(feature = "with-syn")] #[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<quote::Tokens, String> {
let syn_item = syn::parse_macro_input(item).unwrap(); let syn_item = syn::parse_macro_input(item).unwrap();
let (ser, de, syn_item) = strip_serde_derives(syn_item); ser::expand_derive_serialize(&syn_item)
let expanded_ser = if ser { }
Some(try!(ser::expand_derive_serialize(&syn_item)))
} else { #[cfg(feature = "with-syn")]
None #[doc(hidden)]
}; /// Not public API. Use the serde_derive crate.
let expanded_de = if de { pub fn expand_derive_deserialize(item: &str) -> Result<quote::Tokens, String> {
Some(try!(de::expand_derive_deserialize(&syn_item))) let syn_item = syn::parse_macro_input(item).unwrap();
} else { de::expand_derive_deserialize(&syn_item)
None::<quote::Tokens>
};
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)
}
} }
+71 -67
View File
@@ -256,76 +256,80 @@ fn serialize_variant(
let variant_ident = variant.ident.clone(); let variant_ident = variant.ident.clone();
let variant_name = variant.attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name();
match variant.style { if variant.attrs.skip_serializing() {
Style::Unit => { let skipped_msg = format!("The enum variant {}::{} cannot be serialized",
quote! { type_ident, variant_ident);
#type_ident::#variant_ident => let skipped_err = quote! {
_serde::ser::Serializer::serialize_unit_variant( Err(_serde::ser::Error::invalid_value(#skipped_msg))
_serializer, };
#type_name, let fields_pat = match variant.style {
#variant_index, Style::Unit => quote!(),
#variant_name, Style::Newtype | Style::Tuple => quote!( (..) ),
), Style::Struct => quote!( {..} ),
} };
}, quote! {
Style::Newtype => { #type_ident::#variant_ident #fields_pat => #skipped_err,
let block = serialize_newtype_variant(
type_name,
variant_index,
variant_name,
ty,
generics,
&variant.fields[0],
);
quote! {
#type_ident::#variant_ident(ref __simple_value) => #block,
}
},
Style::Tuple => {
let field_names: Vec<Tokens> = (0 .. variant.fields.len())
.map(|i| {
let id = aster::id(format!("__field{}", i));
quote!(ref #id)
})
.collect();
let pat = quote!(#type_ident::#variant_ident(#(#field_names),*));
let block = serialize_tuple_variant(
type_name,
variant_index,
variant_name,
generics,
ty,
&variant.fields,
);
quote! {
#pat => { #block }
}
} }
Style::Struct => { } else { // variant wasn't skipped
let fields = variant.fields.iter().map(|field| { match variant.style {
let id = match field.ident { Style::Unit => {
Some(ref name) => name.clone(), quote! {
None => panic!("struct variant has unnamed fields"), #type_ident::#variant_ident =>
}; _serde::ser::Serializer::serialize_unit_variant(
quote!(ref #id) _serializer,
}); #type_name,
let pat = quote!(#type_ident::#variant_ident { #(#fields),* }); #variant_index,
#variant_name,
),
}
},
Style::Newtype => {
let block = serialize_newtype_variant(
type_name,
variant_index,
variant_name,
ty,
generics,
&variant.fields[0],
);
let block = serialize_struct_variant( quote! {
variant_index, #type_ident::#variant_ident(ref __simple_value) => #block,
variant_name, }
generics, },
ty, Style::Tuple => {
&variant.fields, let field_names = (0 .. variant.fields.len())
item_attrs, .map(|i| aster::id(format!("__field{}", i)));
);
quote! { let block = serialize_tuple_variant(
#pat => { #block } type_name,
variant_index,
variant_name,
generics,
ty,
&variant.fields,
);
quote! {
#type_ident::#variant_ident(#(ref #field_names),*) => { #block }
}
}
Style::Struct => {
let fields = variant.fields.iter()
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
let block = serialize_struct_variant(
variant_index,
variant_name,
generics,
ty,
&variant.fields,
item_attrs,
);
quote! {
#type_ident::#variant_ident { #(ref #fields),* } => { #block }
}
} }
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen_internals" name = "serde_codegen_internals"
version = "0.10.0" version = "0.11.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "AST representation used by Serde codegen. Unstable." description = "AST representation used by Serde codegen. Unstable."
@@ -15,4 +15,4 @@ unstable-testing = ["clippy"]
[dependencies] [dependencies]
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
syn = "0.9" syn = "0.10"
+64 -28
View File
@@ -1,5 +1,7 @@
use Ctxt; use Ctxt;
use syn; use syn;
use syn::MetaItem::{List, NameValue, Word};
use syn::NestedMetaItem::{Literal, MetaItem};
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints // This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Item::from_ast`, `attr::Variant::from_ast`, and // are `attr::Item::from_ast`, `attr::Variant::from_ast`, and
@@ -105,7 +107,7 @@ impl Item {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename="foo")]` // 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) { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
@@ -113,7 +115,7 @@ impl Item {
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // 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) { if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
@@ -121,12 +123,12 @@ impl Item {
} }
// Parse `#[serde(deny_unknown_fields)]` // 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(); deny_unknown_fields.set_true();
} }
// Parse `#[serde(bound="D: Serialize")]` // 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) { if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -134,17 +136,21 @@ impl Item {
} }
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` // 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) { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
ser_bound.set_opt(ser); ser_bound.set_opt(ser);
de_bound.set_opt(de); de_bound.set_opt(de);
} }
} }
_ => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde container attribute `{}`", cx.error(format!("unknown serde container attribute `{}`",
meta_item.name())); meta_item.name()));
} }
Literal(_) => {
cx.error(format!("unexpected literal in serde container attribute"));
}
} }
} }
} }
@@ -181,18 +187,22 @@ impl Item {
#[derive(Debug)] #[derive(Debug)]
pub struct Variant { pub struct Variant {
name: Name, name: Name,
skip_deserializing: bool,
skip_serializing: bool,
} }
impl Variant { impl Variant {
pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self {
let mut ser_name = Attr::none(cx, "rename"); let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename="foo")]` // 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) { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
@@ -200,17 +210,29 @@ impl Variant {
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // 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) { if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
} }
} }
// Parse `#[serde(skip_deserializing)]`
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
skip_deserializing.set_true();
}
// Parse `#[serde(skip_serializing)]`
MetaItem(Word(ref name)) if name == "skip_serializing" => {
skip_serializing.set_true();
}
_ => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`", cx.error(format!("unknown serde variant attribute `{}`",
meta_item.name())); meta_item.name()));
} }
Literal(_) => {
cx.error(format!("unexpected literal in serde variant attribute"));
}
} }
} }
} }
@@ -220,12 +242,22 @@ impl Variant {
serialize: ser_name.get().unwrap_or_else(|| variant.ident.to_string()), serialize: ser_name.get().unwrap_or_else(|| variant.ident.to_string()),
deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()), deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()),
}, },
skip_deserializing: skip_deserializing.get(),
skip_serializing: skip_serializing.get(),
} }
} }
pub fn name(&self) -> &Name { pub fn name(&self) -> &Name {
&self.name &self.name
} }
pub fn skip_deserializing(&self) -> bool {
self.skip_deserializing
}
pub fn skip_serializing(&self) -> bool {
self.skip_serializing
}
} }
/// Represents field attribute information /// Represents field attribute information
@@ -278,7 +310,7 @@ impl Field {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename="foo")]` // 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) { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
@@ -286,7 +318,7 @@ impl Field {
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // 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) { if let Ok((ser, de)) = get_renames(cx, meta_items) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
@@ -294,50 +326,50 @@ impl Field {
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
syn::MetaItem::Word(ref name) if name == "default" => { MetaItem(Word(ref name)) if name == "default" => {
default.set(FieldDefault::Default); default.set(FieldDefault::Default);
} }
// Parse `#[serde(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) { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
default.set(FieldDefault::Path(path)); default.set(FieldDefault::Path(path));
} }
} }
// Parse `#[serde(skip_serializing)]` // 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(); skip_serializing.set_true();
} }
// Parse `#[serde(skip_deserializing)]` // 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(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing_if="...")]` // 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) { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
skip_serializing_if.set(path); skip_serializing_if.set(path);
} }
} }
// Parse `#[serde(serialize_with="...")]` // 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) { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
serialize_with.set(path); serialize_with.set(path);
} }
} }
// Parse `#[serde(deserialize_with="...")]` // 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) { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
deserialize_with.set(path); deserialize_with.set(path);
} }
} }
// Parse `#[serde(bound="D: Serialize")]` // 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) { if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -345,17 +377,21 @@ impl Field {
} }
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` // 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) { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
ser_bound.set_opt(ser); ser_bound.set_opt(ser);
de_bound.set_opt(de); de_bound.set_opt(de);
} }
} }
_ => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde field attribute `{}`", cx.error(format!("unknown serde field attribute `{}`",
meta_item.name())); meta_item.name()));
} }
Literal(_) => {
cx.error(format!("unexpected literal in serde field attribute"));
}
} }
} }
} }
@@ -424,7 +460,7 @@ type SerAndDe<T> = (Option<T>, Option<T>);
fn get_ser_and_de<T, F>( fn get_ser_and_de<T, F>(
cx: &Ctxt, cx: &Ctxt,
attr_name: &'static str, attr_name: &'static str,
items: &[syn::MetaItem], items: &[syn::NestedMetaItem],
f: F f: F
) -> Result<SerAndDe<T>, ()> ) -> Result<SerAndDe<T>, ()>
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>, where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>,
@@ -434,13 +470,13 @@ fn get_ser_and_de<T, F>(
for item in items { for item in items {
match *item { 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) { if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
ser_item.set(v); 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) { if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
de_item.set(v); de_item.set(v);
} }
@@ -459,21 +495,21 @@ fn get_ser_and_de<T, F>(
fn get_renames( fn get_renames(
cx: &Ctxt, cx: &Ctxt,
items: &[syn::MetaItem], items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<String>, ()> { ) -> Result<SerAndDe<String>, ()> {
get_ser_and_de(cx, "rename", items, get_string_from_lit) get_ser_and_de(cx, "rename", items, get_string_from_lit)
} }
fn get_where_predicates( fn get_where_predicates(
cx: &Ctxt, cx: &Ctxt,
items: &[syn::MetaItem], items: &[syn::NestedMetaItem],
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> { ) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where) 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 { 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()) Some(items.iter().cloned().collect())
} }
_ => None _ => None
+4 -7
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "0.8.16" version = "0.8.21"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -14,11 +14,8 @@ include = ["Cargo.toml", "src/**/*.rs"]
name = "serde_derive" name = "serde_derive"
proc-macro = true proc-macro = true
[dependencies]
post-expansion = "0.1.0"
[dependencies.serde_codegen] [dependencies.serde_codegen]
version = "=0.8.16" version = "=0.8.21"
path = "../serde_codegen" path = "../serde_codegen"
default-features = false default-features = false
features = ["with-syn"] features = ["with-syn"]
@@ -26,5 +23,5 @@ features = ["with-syn"]
[dev-dependencies] [dev-dependencies]
compiletest_rs = "^0.2.0" compiletest_rs = "^0.2.0"
fnv = "1.0" fnv = "1.0"
serde = { version = "0.8.16", path = "../serde" } serde = { version = "0.8.21", path = "../serde" }
serde_test = { version = "0.8.16", path = "../serde_test" } serde_test = { version = "0.8.21", path = "../serde_test" }
+4 -12
View File
@@ -1,30 +1,22 @@
#![feature(proc_macro, proc_macro_lib)] #![feature(proc_macro, proc_macro_lib)]
#![cfg(not(test))]
extern crate proc_macro; extern crate proc_macro;
extern crate serde_codegen; extern crate serde_codegen;
#[macro_use]
extern crate post_expansion;
use proc_macro::TokenStream; use proc_macro::TokenStream;
#[proc_macro_derive(Serialize)] #[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Serialize)]\n{}", input); match serde_codegen::expand_derive_serialize(&input.to_string()) {
match serde_codegen::expand_single_item(&item) {
Ok(expanded) => expanded.parse().unwrap(), Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg), Err(msg) => panic!(msg),
} }
} }
#[proc_macro_derive(Deserialize)] #[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Deserialize)]\n{}", input); match serde_codegen::expand_derive_deserialize(&input.to_string()) {
match serde_codegen::expand_single_item(&item) {
Ok(expanded) => expanded.parse().unwrap(), Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg), Err(msg) => panic!(msg),
} }
} }
register_post_expansion!(PostExpansion_serde);
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "0.8.16" version = "0.8.21"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
@@ -12,4 +12,4 @@ keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"] include = ["Cargo.toml", "src/**/*.rs"]
[dependencies] [dependencies]
serde = { version = "0.8.16", path = "../serde" } serde = { version = "0.8.21", path = "../serde" }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_testing" name = "serde_testing"
version = "0.8.16" version = "0.8.21"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
+13 -1
View File
@@ -37,7 +37,10 @@ enum Enum {
Unit, Unit,
Simple(i32), Simple(i32),
Seq(i32, i32, i32), Seq(i32, i32, i32),
Map { a: i32, b: i32, c: i32 } Map { a: i32, b: i32, c: i32 },
#[allow(dead_code)]
#[serde(skip_deserializing)]
Skipped,
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -215,6 +218,9 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_unit_string {
String::new() => &[Token::Unit],
}
test_tuple_struct { test_tuple_struct {
TupleStruct(1, 2, 3) => &[ TupleStruct(1, 2, 3) => &[
Token::SeqStart(Some(3)), Token::SeqStart(Some(3)),
@@ -802,6 +808,12 @@ declare_error_tests! {
], ],
Error::UnknownVariant("Foo".to_owned()), Error::UnknownVariant("Foo".to_owned()),
} }
test_enum_skipped_variant<Enum> {
&[
Token::EnumUnit("Enum", "Skipped"),
],
Error::UnknownVariant("Skipped".to_owned()),
}
test_struct_seq_too_long<Struct> { test_struct_seq_too_long<Struct> {
&[ &[
Token::SeqStart(Some(4)), Token::SeqStart(Some(4)),
+29 -1
View File
@@ -30,12 +30,20 @@ struct Struct {
c: i32, c: i32,
} }
#[derive(Serialize)] #[derive(Serialize, PartialEq, Debug)]
enum Enum { enum Enum {
Unit, Unit,
One(i32), One(i32),
Seq(i32, i32), Seq(i32, i32),
Map { a: i32, b: i32 }, Map { a: i32, b: i32 },
#[serde(skip_serializing)]
SkippedUnit,
#[serde(skip_serializing)]
SkippedOne(i32),
#[serde(skip_serializing)]
SkippedSeq(i32, i32),
#[serde(skip_serializing)]
SkippedMap { _a: i32, _b: i32 },
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -388,3 +396,23 @@ fn test_cannot_serialize_paths() {
&[], &[],
Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned())); Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned()));
} }
#[test]
fn test_enum_skipped() {
assert_ser_tokens_error(
&Enum::SkippedUnit,
&[],
Error::InvalidValue("The enum variant Enum::SkippedUnit cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedOne(42),
&[],
Error::InvalidValue("The enum variant Enum::SkippedOne cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedSeq(1, 2),
&[],
Error::InvalidValue("The enum variant Enum::SkippedSeq cannot be serialized".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedMap { _a: 1, _b: 2 },
&[],
Error::InvalidValue("The enum variant Enum::SkippedMap cannot be serialized".to_owned()));
}