From e9b04de9a5d4691ea1cb68f741ebdedf9af2e70d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Aug 2016 09:37:16 -0400 Subject: [PATCH 01/15] Impl SeqVisitor for MapDeserializer --- serde/src/de/value.rs | 142 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 5 deletions(-) diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index bf3e0631..4fcbd000 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -781,6 +781,15 @@ impl MapDeserializer marker: PhantomData, } } + + fn next(&mut self) -> Option<(K, V)> { + self.iter.next().map(|(k, v)| { + if let Some(len) = self.len.as_mut() { + *len -= 1; + } + (k, v) + }) + } } impl de::Deserializer for MapDeserializer @@ -826,14 +835,11 @@ impl de::MapVisitor for MapDeserializer fn visit_key(&mut self) -> Result, Self::Error> where T: de::Deserialize, { - match self.iter.next() { + match self.next() { Some((key, value)) => { - if let Some(len) = self.len.as_mut() { - *len -= 1; - } self.value = Some(value); let mut de = key.into_deserializer(); - Ok(Some(try!(de::Deserialize::deserialize(&mut de)))) + de::Deserialize::deserialize(&mut de).map(Some) } None => Ok(None), } @@ -867,6 +873,132 @@ impl de::MapVisitor for MapDeserializer } } +impl de::SeqVisitor for MapDeserializer + where I: Iterator, + K: ValueDeserializer, + V: ValueDeserializer, + E: de::Error, +{ + type Error = E; + + fn visit(&mut self) -> Result, Self::Error> + where T: de::Deserialize, + { + match self.next() { + Some(kv) => { + let mut de = PairDeserializer(Some(kv), PhantomData); + de::Deserialize::deserialize(&mut de).map(Some) + } + None => Ok(None), + } + } + + fn end(&mut self) -> Result<(), Self::Error> { + de::MapVisitor::end(self) + } + + fn size_hint(&self) -> (usize, Option) { + de::MapVisitor::size_hint(self) + } +} + +// Used in the `impl SeqVisitor for MapDeserializer` to visit the map as a +// sequence of pairs. +struct PairDeserializer(Option<(A, B)>, PhantomData); + +impl de::Deserializer for PairDeserializer + where A: ValueDeserializer, + B: ValueDeserializer, + E: de::Error +{ + type Error = E; + + de_forward_to_deserialize!{ + deserialize_bool, + deserialize_f64, deserialize_f32, + deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, + deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, + deserialize_char, deserialize_str, deserialize_string, + deserialize_ignored_any, + deserialize_bytes, + deserialize_unit_struct, deserialize_unit, deserialize_option, + deserialize_map, deserialize_newtype_struct, deserialize_struct_field, + deserialize_tuple, + deserialize_enum, + deserialize_struct, deserialize_tuple_struct + } + + fn deserialize(&mut self, visitor: V) -> Result + where V: de::Visitor, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + match self.0.take() { + Some((k, v)) => { + visitor.visit_seq(PairVisitor(Some(k), Some(v), PhantomData)) + } + None => Err(de::Error::end_of_stream()), + } + } + + fn deserialize_seq_fixed_size(&mut self, len: usize, visitor: V) -> Result + where V: de::Visitor, + { + if len == 2 { + self.deserialize_seq(visitor) + } else { + Err(de::Error::invalid_length(len)) + } + } +} + +struct PairVisitor(Option, Option, PhantomData); + +impl de::SeqVisitor for PairVisitor + where A: ValueDeserializer, + B: ValueDeserializer, + E: de::Error, +{ + type Error = E; + + fn visit(&mut self) -> Result, Self::Error> + where T: de::Deserialize, + { + if let Some(k) = self.0.take() { + let mut de = k.into_deserializer(); + de::Deserialize::deserialize(&mut de).map(Some) + } else if let Some(v) = self.1.take() { + let mut de = v.into_deserializer(); + de::Deserialize::deserialize(&mut de).map(Some) + } else { + Ok(None) + } + } + + fn end(&mut self) -> Result<(), Self::Error> { + if self.1.is_none() { + Ok(()) + } else { + Err(de::Error::invalid_length(self.size_hint().0)) + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = if self.0.is_some() { + 2 + } else if self.1.is_some() { + 1 + } else { + 0 + }; + (len, Some(len)) + } +} + /////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "collections"))] From 278e8eb720b7fe3bf6e3afe6d79e331d1607701d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Aug 2016 10:45:25 -0400 Subject: [PATCH 02/15] Add deserialize_seq methods to MapDeserializer --- serde/src/de/value.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index 4fcbd000..5cb17318 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -806,6 +806,22 @@ impl de::Deserializer for MapDeserializer visitor.visit_map(self) } + fn deserialize_seq(&mut self, mut visitor: V_) -> Result + where V_: de::Visitor, + { + visitor.visit_seq(self) + } + + fn deserialize_seq_fixed_size(&mut self, len: usize, mut visitor: V_) -> Result + where V_: de::Visitor, + { + match self.len { + Some(map_len) if map_len == len => visitor.visit_seq(self), + Some(_) => Err(de::Error::invalid_length(len)), + None => visitor.visit_seq(self), + } + } + de_forward_to_deserialize!{ deserialize_bool, deserialize_f64, deserialize_f32, @@ -815,7 +831,6 @@ impl de::Deserializer for MapDeserializer deserialize_ignored_any, deserialize_bytes, deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, deserialize_map, deserialize_newtype_struct, deserialize_struct_field, deserialize_tuple, deserialize_enum, From f3d566af0926333d428ad16c7b70ecdeb72a1d3e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 28 Aug 2016 08:37:55 -0700 Subject: [PATCH 03/15] Remove clippy shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1cad02db..6e6be364 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) [![Clippy Linting Result](https://clippy.bashy.io/github/serde-rs/serde/master/badge.svg)](https://clippy.bashy.io/github/serde-rs/serde/master/log) +# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** From 7014c105b46e0b9cd01a3b899468d8e81c738a39 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 28 Aug 2016 08:39:53 -0700 Subject: [PATCH 04/15] Remove coverage shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e6be364..9a8839d5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) +# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** From d914fdf67b175b95168f163727578ac0b8d6883b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 28 Aug 2016 22:19:17 -0700 Subject: [PATCH 05/15] Macros 1.1 --- serde_codegen/src/lib.rs | 90 +++++++++++++++++++++++----------------- serde_derive/Cargo.toml | 18 ++++++++ serde_derive/src/lib.rs | 20 +++++++++ tmp_test/Cargo.toml | 9 ++++ tmp_test/build.sh | 32 ++++++++++++++ tmp_test/src/main.rs | 16 +++++++ 6 files changed, 148 insertions(+), 37 deletions(-) create mode 100644 serde_derive/Cargo.toml create mode 100644 serde_derive/src/lib.rs create mode 100644 tmp_test/Cargo.toml create mode 100755 tmp_test/build.sh create mode 100644 tmp_test/src/main.rs diff --git a/serde_codegen/src/lib.rs b/serde_codegen/src/lib.rs index fcdc6f4e..55318af6 100644 --- a/serde_codegen/src/lib.rs +++ b/serde_codegen/src/lib.rs @@ -35,6 +35,58 @@ include!(concat!(env!("OUT_DIR"), "/lib.rs")); #[cfg(not(feature = "with-syntex"))] include!("lib.rs.in"); +#[cfg(feature = "with-syntex")] +fn syntex_registry() -> syntex::Registry { + use syntax::{ast, fold}; + + /// Strip the serde attributes from the crate. + #[cfg(feature = "with-syntex")] + fn strip_attributes(krate: ast::Crate) -> ast::Crate { + /// Helper folder that strips the serde attributes after the extensions have been expanded. + struct StripAttributeFolder; + + impl fold::Folder for StripAttributeFolder { + fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { + match attr.node.value.node { + ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; } + _ => {} + } + + Some(attr) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + fold::Folder::fold_crate(&mut StripAttributeFolder, krate) + } + + let mut reg = syntex::Registry::new(); + + reg.add_attr("feature(custom_derive)"); + reg.add_attr("feature(custom_attribute)"); + + reg.add_decorator("derive_Serialize", ser::expand_derive_serialize); + reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize); + + reg.add_post_expansion_pass(strip_attributes); + + reg +} + +#[cfg(feature = "with-syntex")] +pub fn expand_str(src: &str) -> Result { + let src = src.to_owned(); + + let expand_thread = move || { + syntex_registry().expand_str("", "", &src) + }; + + syntex::with_extra_stack(expand_thread) +} + #[cfg(feature = "with-syntex")] pub fn expand(src: S, dst: D) -> Result<(), syntex::Error> where S: AsRef, @@ -44,43 +96,7 @@ pub fn expand(src: S, dst: D) -> Result<(), syntex::Error> let dst = dst.as_ref().to_owned(); let expand_thread = move || { - use syntax::{ast, fold}; - - /// Strip the serde attributes from the crate. - #[cfg(feature = "with-syntex")] - fn strip_attributes(krate: ast::Crate) -> ast::Crate { - /// Helper folder that strips the serde attributes after the extensions have been expanded. - struct StripAttributeFolder; - - impl fold::Folder for StripAttributeFolder { - fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { - match attr.node.value.node { - ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; } - _ => {} - } - - Some(attr) - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } - } - - fold::Folder::fold_crate(&mut StripAttributeFolder, krate) - } - - let mut reg = syntex::Registry::new(); - - reg.add_attr("feature(custom_derive)"); - reg.add_attr("feature(custom_attribute)"); - - reg.add_decorator("derive_Serialize", ser::expand_derive_serialize); - reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize); - - reg.add_post_expansion_pass(strip_attributes); - - reg.expand("", src, dst) + syntex_registry().expand("", src, dst) }; syntex::with_extra_stack(expand_thread) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml new file mode 100644 index 00000000..8702b267 --- /dev/null +++ b/serde_derive/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "serde_derive" +version = "0.8.4" +authors = ["Erick Tryzelaar "] +license = "MIT/Apache-2.0" +description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" +homepage = "https://serde.rs" +repository = "https://github.com/serde-rs/serde" +documentation = "https://serde.rs/codegen.html" +keywords = ["serde", "serialization"] +include = ["Cargo.toml", "src/**/*.rs"] + +[lib] +name = "serde_derive" +rustc-macro = true + +[dependencies] +serde_codegen = { version = "=0.8.4", path = "../serde_codegen" } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs new file mode 100644 index 00000000..d0cc0ef9 --- /dev/null +++ b/serde_derive/src/lib.rs @@ -0,0 +1,20 @@ +#![feature(rustc_macro)] + +extern crate rustc_macro; +extern crate serde_codegen; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Serialize)] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + let item = format!("#[derive(Serialize)]\n{}", input); + let expanded = serde_codegen::expand_str(&item).unwrap(); + expanded.parse().unwrap() +} + +#[rustc_macro_derive(Deserialize)] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let item = format!("#[derive(Deserialize)]\n{}", input); + let expanded = serde_codegen::expand_str(&item).unwrap(); + expanded.parse().unwrap() +} diff --git a/tmp_test/Cargo.toml b/tmp_test/Cargo.toml new file mode 100644 index 00000000..ba3866cb --- /dev/null +++ b/tmp_test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "tmp-test" +version = "0.1.0" +authors = ["David Tolnay "] + +[dependencies] +serde = "0.8" +serde_derive = { path = "../serde_derive" } +serde_json = "0.8" diff --git a/tmp_test/build.sh b/tmp_test/build.sh new file mode 100755 index 00000000..a2ed781b --- /dev/null +++ b/tmp_test/build.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -xeuo pipefail + +DIR=$(cd "$(dirname "$0")" && pwd) + +export RUSTC=${RUSTC:-$HOME/.local/bin/rustc} + +cargo build || true + +"$RUSTC" \ + "$DIR"/../serde_derive/src/lib.rs \ + --crate-name serde_derive \ + --crate-type rustc-macro \ + -C prefer-dynamic \ + -g \ + --out-dir "$DIR"/target/debug/deps \ + --emit=dep-info,link \ + -L dependency="$DIR"/target/debug/deps \ + --extern serde_codegen="$DIR"/target/debug/deps/libserde_codegen.rlib + +"$RUSTC" \ + src/main.rs \ + --crate-name tmp_test \ + --crate-type bin \ + -g \ + --out-dir "$DIR"/target/debug \ + --emit=dep-info,link \ + -L dependency="$DIR"/target/debug/deps \ + --extern serde_json=$(echo "$DIR"/target/debug/deps/libserde_json-*.rlib) \ + --extern serde=$(echo "$DIR"/target/debug/deps/libserde-*.rlib) \ + --extern serde_derive="$DIR"/target/debug/deps/libserde_derive.so diff --git a/tmp_test/src/main.rs b/tmp_test/src/main.rs new file mode 100644 index 00000000..bc3e30d4 --- /dev/null +++ b/tmp_test/src/main.rs @@ -0,0 +1,16 @@ +#![feature(rustc_macro)] + +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + +#[derive(Serialize)] +enum Macros { + #[serde(rename = "macros 1.1")] + OnePointOne, +} + +fn main() { + let s = Macros::OnePointOne; + println!("{}", serde_json::to_string(&s).unwrap()); +} From 3c45e5c7a5415bcfee9b21ea81c78b60a5165094 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 30 Aug 2016 23:55:08 -0700 Subject: [PATCH 06/15] Next iteration --- serde_derive/src/lib.rs | 2 +- tmp_test/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index d0cc0ef9..f4d592d6 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_macro)] +#![feature(rustc_macro, rustc_macro_lib)] extern crate rustc_macro; extern crate serde_codegen; diff --git a/tmp_test/src/main.rs b/tmp_test/src/main.rs index bc3e30d4..8e4c43b6 100644 --- a/tmp_test/src/main.rs +++ b/tmp_test/src/main.rs @@ -4,7 +4,7 @@ extern crate serde_derive; extern crate serde_json; -#[derive(Serialize)] +#[derive(Serialize, Deserialize)] enum Macros { #[serde(rename = "macros 1.1")] OnePointOne, From 4bb92790748cd89449a1969b807ac31373e84bb8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 31 Aug 2016 12:53:27 -0700 Subject: [PATCH 07/15] Bump syntex to 0.43 --- serde/Cargo.toml | 2 +- serde_codegen/Cargo.toml | 18 ++++----- serde_codegen_internals/Cargo.toml | 6 +-- serde_codegen_internals/src/attr.rs | 58 +++++++++++++++++++---------- serde_macros/Cargo.toml | 8 ++-- serde_test/Cargo.toml | 4 +- testing/Cargo.toml | 2 +- 7 files changed, 59 insertions(+), 39 deletions(-) diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 59ffaf2a..95064905 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" diff --git a/serde_codegen/Cargo.toml b/serde_codegen/Cargo.toml index 36f705a5..9bf5a783 100644 --- a/serde_codegen/Cargo.toml +++ b/serde_codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_codegen" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" @@ -25,14 +25,14 @@ with-syntex = [ ] [build-dependencies] -quasi_codegen = { version = "^0.18.0", optional = true } -syntex = { version = "^0.42.2", optional = true } +quasi_codegen = { version = "^0.19.0", optional = true } +syntex = { version = "^0.43.0", optional = true } [dependencies] -aster = { version = "^0.25.0", default-features = false } +aster = { version = "^0.26.0", default-features = false } clippy = { version = "^0.*", optional = true } -quasi = { version = "^0.18.0", default-features = false } -quasi_macros = { version = "^0.18.0", optional = true } -serde_codegen_internals = { version = "=0.7.0", default-features = false, path = "../serde_codegen_internals" } -syntex = { version = "^0.42.2", optional = true } -syntex_syntax = { version = "^0.42.0", optional = true } +quasi = { version = "^0.19.0", default-features = false } +quasi_macros = { version = "^0.19.0", optional = true } +serde_codegen_internals = { version = "=0.8.0", default-features = false, path = "../serde_codegen_internals" } +syntex = { version = "^0.43.0", optional = true } +syntex_syntax = { version = "^0.43.0", optional = true } diff --git a/serde_codegen_internals/Cargo.toml b/serde_codegen_internals/Cargo.toml index 95750d3e..3219579d 100644 --- a/serde_codegen_internals/Cargo.toml +++ b/serde_codegen_internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_codegen_internals" -version = "0.7.0" +version = "0.8.0" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "AST representation used by Serde codegen. Unstable." @@ -17,5 +17,5 @@ with-syntex = ["syntex_syntax", "syntex_errors"] [dependencies] clippy = { version = "^0.*", optional = true } -syntex_syntax = { version = "^0.42.0", optional = true } -syntex_errors = { version = "^0.42.0", optional = true } +syntex_syntax = { version = "^0.43.0", optional = true } +syntex_errors = { version = "^0.43.0", optional = true } diff --git a/serde_codegen_internals/src/attr.rs b/serde_codegen_internals/src/attr.rs index 8d8d595b..a4dd2ce3 100644 --- a/serde_codegen_internals/src/attr.rs +++ b/serde_codegen_internals/src/attr.rs @@ -8,8 +8,7 @@ use syntax::fold::Folder; use syntax::parse::parser::{Parser, PathStyle}; use syntax::parse::token::{self, InternedString}; use syntax::parse; -use syntax::print::pprust::{lit_to_string, meta_item_to_string}; -use syntax::ptr::P; +use syntax::print::pprust::{lit_to_string, meta_item_to_string, meta_list_item_to_string}; use syntax::tokenstream::{self, TokenTree}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints @@ -165,7 +164,7 @@ impl Item { cx.span_err( meta_item.span, &format!("unknown serde container attribute `{}`", - meta_item_to_string(meta_item))); + meta_item_to_string(&meta_item))); } } } @@ -236,7 +235,7 @@ impl Variant { cx.span_err( meta_item.span, &format!("unknown serde variant attribute `{}`", - meta_item_to_string(meta_item))); + meta_item_to_string(&meta_item))); } } } @@ -384,7 +383,7 @@ impl Field { cx.span_err( meta_item.span, &format!("unknown serde field attribute `{}`", - meta_item_to_string(meta_item))); + meta_item_to_string(&meta_item))); } } } @@ -454,7 +453,7 @@ type SerAndDe = (Option>, Option>); fn get_ser_and_de( cx: &ExtCtxt, attribute: &'static str, - items: &[P], + items: &[ast::NestedMetaItem], f: F ) -> Result, ()> where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result, @@ -464,15 +463,29 @@ fn get_ser_and_de( for item in items { match item.node { - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => { - if let Ok(v) = f(cx, name, lit) { - ser_item.set(item.span, v); - } - } + ast::NestedMetaItemKind::MetaItem(ref meta_item) => { + match meta_item.node { + ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => { + if let Ok(v) = f(cx, name, lit) { + ser_item.set(item.span, v); + } + } - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => { - if let Ok(v) = f(cx, name, lit) { - de_item.set(item.span, v); + ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => { + if let Ok(v) = f(cx, name, lit) { + de_item.set(item.span, v); + } + } + + _ => { + cx.span_err( + item.span, + &format!("unknown {} attribute `{}`", + attribute, + meta_item_to_string(meta_item))); + + return Err(()); + } } } @@ -481,7 +494,7 @@ fn get_ser_and_de( item.span, &format!("unknown {} attribute `{}`", attribute, - meta_item_to_string(item))); + meta_list_item_to_string(item))); return Err(()); } @@ -493,23 +506,30 @@ fn get_ser_and_de( fn get_renames( cx: &ExtCtxt, - items: &[P], + items: &[ast::NestedMetaItem], ) -> Result, ()> { get_ser_and_de(cx, "rename", items, get_str_from_lit) } fn get_where_predicates( cx: &ExtCtxt, - items: &[P], + items: &[ast::NestedMetaItem], ) -> Result>, ()> { get_ser_and_de(cx, "bound", items, parse_lit_into_where) } -pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P]> { +pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option> { match attr.node.value.node { ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => { attr::mark_used(attr); - Some(items) + Some(items.iter().filter_map(|item| { + match item.node { + ast::NestedMetaItemKind::MetaItem(ref meta_item) => { + Some((*meta_item.clone()).clone()) + } + _ => None, + } + }).collect()) } _ => None } diff --git a/serde_macros/Cargo.toml b/serde_macros/Cargo.toml index f9c832d2..805c8647 100644 --- a/serde_macros/Cargo.toml +++ b/serde_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_macros" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" @@ -23,14 +23,14 @@ unstable-testing = [ [dependencies] clippy = { version = "^0.*", optional = true } -serde_codegen = { version = "=0.8.4", default-features = false, features = ["unstable"], path = "../serde_codegen" } +serde_codegen = { version = "=0.8.5", default-features = false, features = ["unstable"], path = "../serde_codegen" } [dev-dependencies] compiletest_rs = "^0.2.0" fnv = "1.0" rustc-serialize = "^0.3.16" -serde = { version = "0.8.4", path = "../serde" } -serde_test = { version = "0.8.4", path = "../serde_test" } +serde = { version = "0.8.5", path = "../serde" } +serde_test = { version = "0.8.5", path = "../serde_test" } [[test]] name = "test" diff --git a/serde_test/Cargo.toml b/serde_test/Cargo.toml index 878164e5..5ebf58a1 100644 --- a/serde_test/Cargo.toml +++ b/serde_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_test" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] 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.4", path = "../serde" } +serde = { version = "0.8.5", path = "../serde" } diff --git a/testing/Cargo.toml b/testing/Cargo.toml index 9f9fe69e..b21f8889 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_testing" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" From 54cee86fd3b8e600b712c6dd3ee733a1c85ea90d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 31 Aug 2016 20:14:44 -0700 Subject: [PATCH 08/15] Bump to 0.8.5 --- serde_derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 8702b267..50629ffc 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -15,4 +15,4 @@ name = "serde_derive" rustc-macro = true [dependencies] -serde_codegen = { version = "=0.8.4", path = "../serde_codegen" } +serde_codegen = { version = "=0.8.5", path = "../serde_codegen" } From cdb0e6c899cd857ee069c73ed05be64b154e12a6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 31 Aug 2016 21:05:40 -0700 Subject: [PATCH 09/15] Remove build script in favor of rust-lang/cargo#3064 --- tmp_test/build.sh | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100755 tmp_test/build.sh diff --git a/tmp_test/build.sh b/tmp_test/build.sh deleted file mode 100755 index a2ed781b..00000000 --- a/tmp_test/build.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -set -xeuo pipefail - -DIR=$(cd "$(dirname "$0")" && pwd) - -export RUSTC=${RUSTC:-$HOME/.local/bin/rustc} - -cargo build || true - -"$RUSTC" \ - "$DIR"/../serde_derive/src/lib.rs \ - --crate-name serde_derive \ - --crate-type rustc-macro \ - -C prefer-dynamic \ - -g \ - --out-dir "$DIR"/target/debug/deps \ - --emit=dep-info,link \ - -L dependency="$DIR"/target/debug/deps \ - --extern serde_codegen="$DIR"/target/debug/deps/libserde_codegen.rlib - -"$RUSTC" \ - src/main.rs \ - --crate-name tmp_test \ - --crate-type bin \ - -g \ - --out-dir "$DIR"/target/debug \ - --emit=dep-info,link \ - -L dependency="$DIR"/target/debug/deps \ - --extern serde_json=$(echo "$DIR"/target/debug/deps/libserde_json-*.rlib) \ - --extern serde=$(echo "$DIR"/target/debug/deps/libserde-*.rlib) \ - --extern serde_derive="$DIR"/target/debug/deps/libserde_derive.so From 87a402a7513892f432f5342b5816472b65cd7fce Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 11:17:35 -0700 Subject: [PATCH 10/15] Remove rustc_macro test crate --- tmp_test/Cargo.toml | 9 --------- tmp_test/src/main.rs | 16 ---------------- 2 files changed, 25 deletions(-) delete mode 100644 tmp_test/Cargo.toml delete mode 100644 tmp_test/src/main.rs diff --git a/tmp_test/Cargo.toml b/tmp_test/Cargo.toml deleted file mode 100644 index ba3866cb..00000000 --- a/tmp_test/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tmp-test" -version = "0.1.0" -authors = ["David Tolnay "] - -[dependencies] -serde = "0.8" -serde_derive = { path = "../serde_derive" } -serde_json = "0.8" diff --git a/tmp_test/src/main.rs b/tmp_test/src/main.rs deleted file mode 100644 index 8e4c43b6..00000000 --- a/tmp_test/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(rustc_macro)] - -#[macro_use] -extern crate serde_derive; -extern crate serde_json; - -#[derive(Serialize, Deserialize)] -enum Macros { - #[serde(rename = "macros 1.1")] - OnePointOne, -} - -fn main() { - let s = Macros::OnePointOne; - println!("{}", serde_json::to_string(&s).unwrap()); -} From 88d845c4d1ff8453a7c321b4efa1fb95b6aa0d99 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 21:28:40 -0700 Subject: [PATCH 11/15] Include! test suite for serde_derive --- serde_derive/Cargo.toml | 5 +++++ serde_derive/src/lib.rs | 1 + serde_derive/tests/test.rs | 8 ++++++++ 3 files changed, 14 insertions(+) create mode 100644 serde_derive/tests/test.rs diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 50629ffc..6384da20 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -16,3 +16,8 @@ rustc-macro = true [dependencies] serde_codegen = { version = "=0.8.5", path = "../serde_codegen" } + +[dev-dependencies] +fnv = "1.0" +serde = { version = "0.8.5", path = "../serde" } +serde_test = { version = "0.8.5", path = "../serde_test" } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index f4d592d6..aa7bba60 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -1,4 +1,5 @@ #![feature(rustc_macro, rustc_macro_lib)] +#![cfg(not(test))] extern crate rustc_macro; extern crate serde_codegen; diff --git a/serde_derive/tests/test.rs b/serde_derive/tests/test.rs new file mode 100644 index 00000000..ff8ac572 --- /dev/null +++ b/serde_derive/tests/test.rs @@ -0,0 +1,8 @@ +#![feature(test, rustc_macro, rustc_attrs)] + +#[macro_use] +extern crate serde_derive; + +extern crate test; + +include!("../../testing/tests/test.rs.in"); From ac1128a64711f309cf02afae2a9156523083ddd7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 21:28:58 -0700 Subject: [PATCH 12/15] Update serde_derive to 0.8.5 --- serde_derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 6384da20..314080d1 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_derive" -version = "0.8.4" +version = "0.8.5" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" From 248d937f9a969a5dec5ffef7ae0e100e3c3fec5f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 22:06:12 -0700 Subject: [PATCH 13/15] Release 0.8.6 --- serde/Cargo.toml | 2 +- serde_codegen/Cargo.toml | 2 +- serde_derive/Cargo.toml | 8 ++++---- serde_macros/Cargo.toml | 8 ++++---- serde_test/Cargo.toml | 4 ++-- testing/Cargo.toml | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 95064905..748d2938 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" diff --git a/serde_codegen/Cargo.toml b/serde_codegen/Cargo.toml index 9bf5a783..0d119459 100644 --- a/serde_codegen/Cargo.toml +++ b/serde_codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_codegen" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 314080d1..b2434f98 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_derive" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" @@ -15,9 +15,9 @@ name = "serde_derive" rustc-macro = true [dependencies] -serde_codegen = { version = "=0.8.5", path = "../serde_codegen" } +serde_codegen = { version = "=0.8.6", path = "../serde_codegen" } [dev-dependencies] fnv = "1.0" -serde = { version = "0.8.5", path = "../serde" } -serde_test = { version = "0.8.5", path = "../serde_test" } +serde = { version = "0.8.6", path = "../serde" } +serde_test = { version = "0.8.6", path = "../serde_test" } diff --git a/serde_macros/Cargo.toml b/serde_macros/Cargo.toml index 805c8647..21f056f8 100644 --- a/serde_macros/Cargo.toml +++ b/serde_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_macros" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" @@ -23,14 +23,14 @@ unstable-testing = [ [dependencies] clippy = { version = "^0.*", optional = true } -serde_codegen = { version = "=0.8.5", default-features = false, features = ["unstable"], path = "../serde_codegen" } +serde_codegen = { version = "=0.8.6", default-features = false, features = ["unstable"], path = "../serde_codegen" } [dev-dependencies] compiletest_rs = "^0.2.0" fnv = "1.0" rustc-serialize = "^0.3.16" -serde = { version = "0.8.5", path = "../serde" } -serde_test = { version = "0.8.5", path = "../serde_test" } +serde = { version = "0.8.6", path = "../serde" } +serde_test = { version = "0.8.6", path = "../serde_test" } [[test]] name = "test" diff --git a/serde_test/Cargo.toml b/serde_test/Cargo.toml index 5ebf58a1..daaec554 100644 --- a/serde_test/Cargo.toml +++ b/serde_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_test" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] 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.5", path = "../serde" } +serde = { version = "0.8.6", path = "../serde" } diff --git a/testing/Cargo.toml b/testing/Cargo.toml index b21f8889..7b507399 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_testing" -version = "0.8.5" +version = "0.8.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" From 869ebd9e4e8bbe646d790f49d95f9ec609fe9001 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 2 Sep 2016 17:22:58 -0700 Subject: [PATCH 14/15] Remove `if !false { ... }` from generated serialization code --- serde_codegen/src/ser.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 266dc482..ed2f5589 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -532,19 +532,21 @@ fn serialize_tuple_struct_visitor( }; let skip = field.attrs.skip_serializing_if() - .map(|path| quote_expr!(cx, $path($field_expr))) - .unwrap_or(quote_expr!(cx, false)); + .map(|path| quote_expr!(cx, $path($field_expr))); if let Some(path) = field.attrs.serialize_with() { field_expr = wrap_serialize_with(cx, builder, &structure_ty, generics, &field.ty, path, field_expr); } - quote_stmt!(cx, - if !$skip { - try!(_serializer.$func(&mut state, $field_expr)); - } - ).unwrap() + let ser = quote_stmt!(cx, + try!(_serializer.$func(&mut state, $field_expr)); + ).unwrap(); + + match skip { + None => ser, + Some(skip) => quote_stmt!(cx, if !$skip { $ser }).unwrap(), + } }) .collect() } @@ -571,19 +573,21 @@ fn serialize_struct_visitor( let key_expr = name_expr(builder, field.attrs.name()); let skip = field.attrs.skip_serializing_if() - .map(|path| quote_expr!(cx, $path($field_expr))) - .unwrap_or(quote_expr!(cx, false)); + .map(|path| quote_expr!(cx, $path($field_expr))); if let Some(path) = field.attrs.serialize_with() { field_expr = wrap_serialize_with(cx, builder, &structure_ty, generics, &field.ty, path, field_expr) } - quote_stmt!(cx, - if !$skip { - try!(_serializer.$func(&mut state, $key_expr, $field_expr)); - } - ).unwrap() + let ser = quote_stmt!(cx, + try!(_serializer.$func(&mut state, $key_expr, $field_expr)); + ).unwrap(); + + match skip { + None => ser, + Some(skip) => quote_stmt!(cx, if !$skip { $ser }).unwrap(), + } }) .collect() } From d1ce4d62c919befbe37e84b2c18959e95aabe73a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 2 Sep 2016 18:07:26 -0700 Subject: [PATCH 15/15] Change to expression so that syntex keeps the semicolon --- serde_codegen/src/ser.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index ed2f5589..d3c91396 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -539,12 +539,12 @@ fn serialize_tuple_struct_visitor( &structure_ty, generics, &field.ty, path, field_expr); } - let ser = quote_stmt!(cx, + let ser = quote_expr!(cx, try!(_serializer.$func(&mut state, $field_expr)); - ).unwrap(); + ); match skip { - None => ser, + None => quote_stmt!(cx, $ser).unwrap(), Some(skip) => quote_stmt!(cx, if !$skip { $ser }).unwrap(), } }) @@ -580,12 +580,12 @@ fn serialize_struct_visitor( &structure_ty, generics, &field.ty, path, field_expr) } - let ser = quote_stmt!(cx, + let ser = quote_expr!(cx, try!(_serializer.$func(&mut state, $key_expr, $field_expr)); - ).unwrap(); + ); match skip { - None => ser, + None => quote_stmt!(cx, $ser).unwrap(), Some(skip) => quote_stmt!(cx, if !$skip { $ser }).unwrap(), } })