Compare commits

...

28 Commits

Author SHA1 Message Date
Erick Tryzelaar fd5ab8c5c8 feat(cargo): Version bump 2016-02-13 22:06:08 -08:00
Erick Tryzelaar 39fa78e2ec Merge pull request #236 from debris/rustup3
Update serde_codegen for rustc 1.8.0-nightly (ce4b75f25 2016-02-12)
2016-02-13 21:56:07 -08:00
debris e18416ac7f updated serde_tests deps 2016-02-14 03:43:37 +01:00
debris b63cc13f3a updated clippy to 0.0.41 2016-02-14 03:33:58 +01:00
debris 74b230c183 Update serde_codegen for rustc 1.8.0-nightly (ce4b75f25 2016-02-12) 2016-02-14 03:27:20 +01:00
Erick Tryzelaar 064241f03c fix(serde): Rename visit_struct_key to visit_struct_field
This is more consistent with the rest of the serde naming patterns.
2016-02-12 21:22:42 -08:00
Erick Tryzelaar 32163cd53b feat(cargo): Version bump 2016-02-12 21:06:47 -08:00
Erick Tryzelaar 3a5aa00262 fix(codegen): Fix clippy cfg_attr 2016-02-12 20:21:52 -08:00
Erick Tryzelaar 7a3e3a61f4 chore(tests): Silence some warnings 2016-02-08 13:37:03 -08:00
Erick Tryzelaar 517c2f79b7 chore(cargo): Only depend on clippy when testing 2016-02-08 13:35:26 -08:00
Erick Tryzelaar 3cde6fa333 Merge pull request #228 from compressed/clippy
fix(clippy): make clippy optional
2016-02-08 11:20:54 -08:00
Christopher Brickley da7bb8e109 fix(clippy): make clippy optional 2016-02-07 13:59:15 -05:00
Erick Tryzelaar 718822449f Merge pull request #227 from serde-rs/oli-obk-patch-1
add a build.rs file to the stable-only syntex example
2016-02-05 07:54:56 -08:00
Oliver Schneider 43624e8e7f add a build.rs file to the stable-only syntex example 2016-02-05 12:30:28 +01:00
Erick Tryzelaar 4507eaec5b Use deserializer.visit_string for PathBuf 2016-01-28 09:45:38 -08:00
Erick Tryzelaar b3212f4c2b Merge pull request #223 from jwilm/hinting-for-struct-keys
feat(de): Support struct key hinting
2016-01-28 08:57:16 -08:00
Joe Wilm 6d25fc9dbb feat(de): Support struct key hinting
Formats that do not provide type hints in the serialized format
(bincode, redis) rely on hinting in the deserializer. Struct key hinting
was not previously supported. This was not an issue in the past because
bincode serializes structs as a keyless sequence of values. However,
redis data is stored (key, value, key, value, ...), and the keys must be
deserialized to properly create a struct.

The default implementation of `visit_struct_key` is simply `visit` since
that was the previous method called in codegen.
2016-01-28 08:38:07 -08:00
Simon Persson a5d0703e44 Bump clippy dependency to compile on 1.8. 2016-01-23 16:15:31 -08:00
Erick Tryzelaar 0a32cea26e feat(impls): Allow options to be deserialized from units 2016-01-23 16:07:50 -08:00
Erick Tryzelaar da4e37d3f5 docs(tradeoffs): Add section that describes tradeoffs for option types 2016-01-20 11:15:43 -08:00
Erick Tryzelaar 3f9cbc157a fix(cargo): serde_codegen shouldn't depend on '*' serde dependencies 2016-01-18 13:15:09 -08:00
Erick Tryzelaar a51f930101 feat(cargo): Version bump 2016-01-18 13:11:16 -08:00
Erick Tryzelaar 77edd8e544 fix(clippy): Switch to using or_else when we get a str parse error 2016-01-18 13:07:30 -08:00
Erick Tryzelaar 8087b7cec6 fix(cargo): Bump clippy version 2016-01-18 13:00:21 -08:00
Erick Tryzelaar 8df841f048 fix(errors): Report errors on unknown #[serde(...)] attributes
Closes #51, #175, and #187
2016-01-18 12:39:46 -08:00
Erick Tryzelaar bfa2b69193 feat(clippy): Use clippy for it's extra lints 2016-01-18 12:24:03 -08:00
Erick Tryzelaar fbcf905c9f Merge pull request #210 from erickt/v0.6.x
feat(errors): Don't panic if annotating a non-struct/enum
2016-01-16 15:06:07 -08:00
Erick Tryzelaar 979a4bcd88 feat(errors): Don't panic if annotating a non-struct/enum
This also improves the error spans when there's an internal
error.

Closes #206.
2016-01-16 14:51:11 -08:00
29 changed files with 654 additions and 305 deletions
+4 -2
View File
@@ -22,9 +22,11 @@ script:
- | - |
(cd serde && travis-cargo build) && (cd serde && travis-cargo build) &&
(cd serde && travis-cargo test) && (cd serde && travis-cargo test) &&
(cd serde && travis-cargo --only nightly test -- --features nightly-testing) &&
(cd serde_tests && travis-cargo test) && (cd serde_tests && travis-cargo test) &&
(cd serde_macros && travis-cargo --only nightly test) && (cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing) &&
(cd serde_macros && travis-cargo --only nightly bench) && (cd serde_macros && travis-cargo --only nightly test -- --features nightly-testing) &&
(cd serde_macros && travis-cargo --only nightly bench -- --features nightly-testing) &&
(cd serde && travis-cargo --only stable doc) && (cd serde && travis-cargo --only stable doc) &&
(cd serde_codegen && travis-cargo --only stable doc) (cd serde_codegen && travis-cargo --only stable doc)
+85
View File
@@ -129,6 +129,28 @@ fn main() {
} }
``` ```
`build.rs`
```rust
extern crate syntex;
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/main.rs.in");
let dst = Path::new(&out_dir).join("main.rs");
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
```
This also produces: This also produces:
``` ```
@@ -579,6 +601,69 @@ impl serde::de::Visitor for PointVisitor {
} }
``` ```
Design Considerations and tradeoffs for Serializers and Deserializers
=====================================================================
Serde serialization and deserialization implementations are written in such a
way that they err on being able to represent more values, and also provide
better error messages when they are passed an incorrect type to deserialize
from. For example, by default, it is a syntax error to deserialize a `String`
into an `Option<String>`. This is implemented such that it is possible to
distinguish between the values `None` and `Some(())`, if the serialization
format supports option types.
However, many formats do not have option types, and represents optional values
as either a `null`, or some other value. Serde `Serializer`s and
`Deserializer`s can opt-in support for this. For serialization, this is pretty
easy. Simply implement these methods:
```rust
...
fn visit_none(&mut self) -> Result<(), Self::Error> {
self.visit_unit()
}
fn visit_some<T>(&mut self, value: T) -> Result<(), Self::Error> {
value.serialize(self)
}
...
```
For deserialization, this can be implemented by way of the
`Deserializer::visit_option` hook, which presumes that there is some ability to peek at what is the
next value in the serialized token stream. This following example is from
[serde_tests::TokenDeserializer](https://github.com/serde-rs/serde/blob/master/serde_tests/tests/token.rs#L435-L454),
where it checks to see if the next value is an `Option`, a `()`, or some other
value:
```rust
...
fn visit_option<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
where V: de::Visitor,
{
match self.tokens.peek() {
Some(&Token::Option(false)) => {
self.tokens.next();
visitor.visit_none()
}
Some(&Token::Option(true)) => {
self.tokens.next();
visitor.visit_some(self)
}
Some(&Token::Unit) => {
self.tokens.next();
visitor.visit_none()
}
Some(_) => visitor.visit_some(self),
None => Err(Error::EndOfStreamError),
}
}
...
```
Annotations Annotations
=========== ===========
+7 -6
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "0.6.7" version = "0.6.13"
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"
@@ -9,12 +9,13 @@ documentation = "https://serde-rs.github.io/serde/serde/serde/index.html"
readme = "../README.md" readme = "../README.md"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
[dependencies]
num = "^0.1.27"
[features] [features]
nightly = [] nightly-testing = ["clippy"]
num-impls = ["num-bigint", "num-complex", "num-rational"]
num-bigint = ["num/bigint"] num-bigint = ["num/bigint"]
num-complex = ["num/complex"] num-complex = ["num/complex"]
num-impls = ["num-bigint", "num-complex", "num-rational"]
num-rational = ["num/rational"] num-rational = ["num/rational"]
[dependencies]
clippy = { version = "^0.0.41", optional = true }
num = { version = "^0.1.27", default-features = false }
+14 -5
View File
@@ -154,7 +154,9 @@ impl<
fn visit_str<E>(&mut self, v: &str) -> Result<T, E> fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
where E: Error, where E: Error,
{ {
str::FromStr::from_str(v.trim()).or(Err(Error::type_mismatch(Type::Str))) str::FromStr::from_str(v.trim()).or_else(|_| {
Err(Error::type_mismatch(Type::Str))
})
} }
} }
@@ -234,7 +236,7 @@ impl Visitor for StringVisitor {
fn visit_str<E>(&mut self, v: &str) -> Result<String, E> fn visit_str<E>(&mut self, v: &str) -> Result<String, E>
where E: Error, where E: Error,
{ {
Ok(v.to_string()) Ok(v.to_owned())
} }
fn visit_string<E>(&mut self, v: String) -> Result<String, E> fn visit_string<E>(&mut self, v: String) -> Result<String, E>
@@ -247,12 +249,12 @@ impl Visitor for StringVisitor {
where E: Error, where E: Error,
{ {
match str::from_utf8(v) { match str::from_utf8(v) {
Ok(s) => Ok(s.to_string()), Ok(s) => Ok(s.to_owned()),
Err(_) => Err(Error::type_mismatch(Type::String)), Err(_) => Err(Error::type_mismatch(Type::String)),
} }
} }
fn visit_byte_buf<'a, E>(&mut self, v: Vec<u8>) -> Result<String, E> fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<String, E>
where E: Error, where E: Error,
{ {
match String::from_utf8(v) { match String::from_utf8(v) {
@@ -281,6 +283,13 @@ impl<
> Visitor for OptionVisitor<T> { > Visitor for OptionVisitor<T> {
type Value = Option<T>; type Value = Option<T>;
#[inline]
fn visit_unit<E>(&mut self) -> Result<Option<T>, E>
where E: Error,
{
Ok(None)
}
#[inline] #[inline]
fn visit_none<E>(&mut self) -> Result<Option<T>, E> fn visit_none<E>(&mut self) -> Result<Option<T>, E>
where E: Error, where E: Error,
@@ -753,7 +762,7 @@ impl Deserialize for path::PathBuf {
fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error>
where D: Deserializer, where D: Deserializer,
{ {
deserializer.visit(PathBufVisitor) deserializer.visit_string(PathBufVisitor)
} }
} }
+10
View File
@@ -403,6 +403,16 @@ pub trait Deserializer {
self.visit_seq(visitor) self.visit_seq(visitor)
} }
/// This method hints that the `Deserialize` type is expecting some sort of struct key mapping.
/// This allows deserializers to choose between &str, usize, or &[u8] to properly deserialize a
/// struct key.
#[inline]
fn visit_struct_field<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor,
{
self.visit(visitor)
}
/// Specify a format string for the deserializer. /// Specify a format string for the deserializer.
/// ///
/// The deserializer format is used to determine which format /// The deserializer format is used to determine which format
+4 -1
View File
@@ -10,7 +10,10 @@
//! [github repository](https://github.com/serde-rs/serde) //! [github repository](https://github.com/serde-rs/serde)
#![doc(html_root_url="https://serde-rs.github.io/serde/serde")] #![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
#![cfg_attr(feature = "nightly", feature(collections, enumset, nonzero, step_trait, zero_one))] #![cfg_attr(feature = "nightly", feature(collections, enumset, nonzero, plugin, step_trait,
zero_one))]
#![cfg_attr(feature = "nightly", plugin(clippy))]
#![cfg_attr(feature = "nightly", allow(linkedlist))]
#![deny(missing_docs)] #![deny(missing_docs)]
+2 -2
View File
@@ -566,8 +566,8 @@ impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
{ {
match self.iter.next() { match self.iter.next() {
Some((key, value)) => { Some((key, value)) => {
let value = try!(serializer.visit_map_elt(key, value)); try!(serializer.visit_map_elt(key, value));
Ok(Some(value)) Ok(Some(()))
} }
None => Ok(None) None => Ok(None)
} }
+2
View File
@@ -322,6 +322,7 @@ pub trait Serializer {
} }
/// A trait that is used by a `Serialize` to iterate through a sequence. /// A trait that is used by a `Serialize` to iterate through a sequence.
#[cfg_attr(feature = "nightly", allow(len_without_is_empty))]
pub trait SeqVisitor { pub trait SeqVisitor {
/// Serializes a sequence item in the serializer. /// Serializes a sequence item in the serializer.
/// ///
@@ -338,6 +339,7 @@ pub trait SeqVisitor {
} }
/// A trait that is used by a `Serialize` to iterate through a map. /// A trait that is used by a `Serialize` to iterate through a map.
#[cfg_attr(feature = "nightly", allow(len_without_is_empty))]
pub trait MapVisitor { pub trait MapVisitor {
/// Serializes a map item in the serializer. /// Serializes a map item in the serializer.
/// ///
+10 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen" name = "serde_codegen"
version = "0.6.9" version = "0.6.13"
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"
@@ -12,15 +12,17 @@ keywords = ["serde", "serialization"]
[features] [features]
default = ["with-syntex"] default = ["with-syntex"]
nightly = ["quasi_macros"] nightly = ["quasi_macros"]
nightly-testing = ["clippy"]
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"] with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
[build-dependencies] [build-dependencies]
quasi_codegen = { version = "^0.4.0", optional = true } quasi_codegen = { version = "^0.6.0", optional = true }
syntex = { version = "^0.26.0", optional = true } syntex = { version = "^0.28.0", optional = true }
[dependencies] [dependencies]
aster = { version = "^0.10.0", default-features = false } aster = { version = "^0.12.0", default-features = false }
quasi = { version = "^0.4.0", default-features = false } clippy = { version = "^0.0.41", optional = true }
quasi_macros = { version = "^0.4.0", optional = true } quasi = { version = "^0.6.0", default-features = false }
syntex = { version = "^0.26.0", optional = true } quasi_macros = { version = "^0.6.0", optional = true }
syntex_syntax = { version = "^0.26.0", optional = true } syntex = { version = "^0.28.0", optional = true }
syntex_syntax = { version = "^0.28.0", optional = true }
+98 -26
View File
@@ -4,6 +4,7 @@ use std::collections::HashSet;
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::print::pprust::meta_item_to_string;
use syntax::ptr::P; use syntax::ptr::P;
use aster; use aster;
@@ -32,7 +33,7 @@ impl FieldAttrs {
/// Return a set of formats that the field has attributes for. /// Return a set of formats that the field has attributes for.
pub fn formats(&self) -> HashSet<P<ast::Expr>> { pub fn formats(&self) -> HashSet<P<ast::Expr>> {
match self.names { match self.names {
FieldNames::Format{ref formats, default: _} => { FieldNames::Format { ref formats, .. } => {
let mut set = HashSet::new(); let mut set = HashSet::new();
for (fmt, _) in formats.iter() { for (fmt, _) in formats.iter() {
set.insert(fmt.clone()); set.insert(fmt.clone());
@@ -70,7 +71,7 @@ impl FieldAttrs {
pub fn default_key_expr(&self) -> &P<ast::Expr> { pub fn default_key_expr(&self) -> &P<ast::Expr> {
match self.names { match self.names {
FieldNames::Global(ref expr) => expr, FieldNames::Global(ref expr) => expr,
FieldNames::Format{formats: _, ref default} => default, FieldNames::Format { ref default, .. } => default,
} }
} }
@@ -104,6 +105,7 @@ impl FieldAttrs {
} }
pub struct FieldAttrsBuilder<'a> { pub struct FieldAttrsBuilder<'a> {
cx: &'a ExtCtxt<'a>,
builder: &'a aster::AstBuilder, builder: &'a aster::AstBuilder,
skip_serializing_field: bool, skip_serializing_field: bool,
skip_serializing_field_if_empty: bool, skip_serializing_field_if_empty: bool,
@@ -114,8 +116,10 @@ pub struct FieldAttrsBuilder<'a> {
} }
impl<'a> FieldAttrsBuilder<'a> { impl<'a> FieldAttrsBuilder<'a> {
pub fn new(builder: &'a aster::AstBuilder) -> FieldAttrsBuilder<'a> { pub fn new(cx: &'a ExtCtxt<'a>,
builder: &'a aster::AstBuilder) -> FieldAttrsBuilder<'a> {
FieldAttrsBuilder { FieldAttrsBuilder {
cx: cx,
builder: builder, builder: builder,
skip_serializing_field: false, skip_serializing_field: false,
skip_serializing_field_if_empty: false, skip_serializing_field_if_empty: false,
@@ -126,7 +130,7 @@ impl<'a> FieldAttrsBuilder<'a> {
} }
} }
pub fn field(mut self, field: &ast::StructField) -> FieldAttrsBuilder<'a> { pub fn field(mut self, field: &ast::StructField) -> Result<FieldAttrsBuilder<'a>, ()> {
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => { ast::NamedField(name, _) => {
self.name = Some(self.builder.expr().str(name)); self.name = Some(self.builder.expr().str(name));
@@ -137,33 +141,41 @@ impl<'a> FieldAttrsBuilder<'a> {
self.attrs(&field.node.attrs) self.attrs(&field.node.attrs)
} }
pub fn attrs(self, attrs: &[ast::Attribute]) -> FieldAttrsBuilder<'a> { pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result<FieldAttrsBuilder<'a>, ()> {
attrs.iter().fold(self, FieldAttrsBuilder::attr) for attr in attrs {
self = try!(self.attr(attr));
}
Ok(self)
} }
pub fn attr(self, attr: &ast::Attribute) -> FieldAttrsBuilder<'a> { pub fn attr(mut self, attr: &ast::Attribute) -> Result<FieldAttrsBuilder<'a>, ()> {
match attr.node.value.node { match attr.node.value.node {
ast::MetaList(ref name, ref items) if name == &"serde" => { ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => {
attr::mark_used(&attr); attr::mark_used(&attr);
items.iter().fold(self, FieldAttrsBuilder::meta_item) for item in items {
self = try!(self.meta_item(item));
}
Ok(self)
} }
_ => { _ => {
self Ok(self)
} }
} }
} }
pub fn meta_item(mut self, meta_item: &P<ast::MetaItem>) -> FieldAttrsBuilder<'a> { pub fn meta_item(mut self, meta_item: &P<ast::MetaItem>) -> Result<FieldAttrsBuilder<'a>, ()> {
match meta_item.node { match meta_item.node {
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
let expr = self.builder.expr().build_lit(P(lit.clone())); let expr = self.builder.expr().build_lit(P(lit.clone()));
self.name(expr) Ok(self.name(expr))
} }
ast::MetaList(ref name, ref items) if name == &"rename" => { ast::MetaItemKind::List(ref name, ref items) if name == &"rename" => {
for item in items { for item in items {
match item.node { match item.node {
ast::MetaNameValue(ref name, ref lit) => { ast::MetaItemKind::NameValue(ref name, ref lit) => {
let name = self.builder.expr().str(name); let name = self.builder.expr().str(name);
let expr = self.builder.expr().build_lit(P(lit.clone())); let expr = self.builder.expr().build_lit(P(lit.clone()));
@@ -172,23 +184,27 @@ impl<'a> FieldAttrsBuilder<'a> {
_ => { } _ => { }
} }
} }
self
Ok(self)
} }
ast::MetaWord(ref name) if name == &"default" => { ast::MetaItemKind::Word(ref name) if name == &"default" => {
self.default() Ok(self.default())
} }
ast::MetaWord(ref name) if name == &"skip_serializing" => { ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => {
self.skip_serializing_field() Ok(self.skip_serializing_field())
} }
ast::MetaWord(ref name) if name == &"skip_serializing_if_empty" => { ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_empty" => {
self.skip_serializing_field_if_empty() Ok(self.skip_serializing_field_if_empty())
} }
ast::MetaWord(ref name) if name == &"skip_serializing_if_none" => { ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_none" => {
self.skip_serializing_field_if_none() Ok(self.skip_serializing_field_if_none())
} }
_ => { _ => {
// Ignore unknown meta variables for now. self.cx.span_err(
self meta_item.span,
&format!("unknown serde field attribute `{}`",
meta_item_to_string(meta_item)));
Err(())
} }
} }
} }
@@ -243,3 +259,59 @@ impl<'a> FieldAttrsBuilder<'a> {
} }
} }
} }
/// Represents container (e.g. struct) attribute information
#[derive(Debug)]
pub struct ContainerAttrs;
pub struct ContainerAttrsBuilder<'a> {
cx: &'a ExtCtxt<'a>,
}
impl<'a> ContainerAttrsBuilder<'a> {
pub fn new(cx: &'a ExtCtxt) -> Self {
ContainerAttrsBuilder {
cx: cx,
}
}
pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result<Self, ()> {
for attr in attrs {
self = try!(self.attr(attr));
}
Ok(self)
}
pub fn attr(mut self, attr: &ast::Attribute) -> Result<Self, ()> {
match attr.node.value.node {
ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => {
attr::mark_used(&attr);
for item in items {
self = try!(self.meta_item(item));
}
Ok(self)
}
_ => {
Ok(self)
}
}
}
pub fn meta_item(self, meta_item: &P<ast::MetaItem>) -> Result<Self, ()> {
match meta_item.node {
_ => {
self.cx.span_err(
meta_item.span,
&format!("unknown serde container attribute `{}`",
meta_item_to_string(meta_item)));
Err(())
}
}
}
pub fn build(self) -> ContainerAttrs {
ContainerAttrs
}
}
+150 -134
View File
@@ -29,7 +29,7 @@ pub fn expand_derive_deserialize(
_ => { _ => {
cx.span_err( cx.span_err(
meta_item.span, meta_item.span,
"`derive` may only be applied to structs and enums"); "`#[derive(Deserialize)]` may only be applied to structs and enums");
return; return;
} }
}; };
@@ -37,9 +37,14 @@ pub fn expand_derive_deserialize(
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let generics = match item.node { let generics = match item.node {
ast::ItemStruct(_, ref generics) => generics, ast::ItemKind::Struct(_, ref generics) => generics,
ast::ItemEnum(_, ref generics) => generics, ast::ItemKind::Enum(_, ref generics) => generics,
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Deserialize)]") _ => {
cx.span_err(
meta_item.span,
"`#[derive(Deserialize)]` may only be applied to structs and enums");
return;
}
}; };
let impl_generics = builder.from_generics(generics.clone()) let impl_generics = builder.from_generics(generics.clone())
@@ -52,13 +57,13 @@ pub fn expand_derive_deserialize(
.segment(item.ident).with_generics(impl_generics.clone()).build() .segment(item.ident).with_generics(impl_generics.clone()).build()
.build(); .build();
let body = deserialize_body( let body = match deserialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
cx, Ok(body) => body,
&builder, Err(()) => {
&item, // An error occured, but it should have been reported already.
&impl_generics, return;
ty.clone(), }
); };
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@@ -81,19 +86,24 @@ fn deserialize_body(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
// Note: While we don't have any container attributes, we still want to try to
// parse them so we can report a proper error if we get passed an unknown attribute.
let _ = try!(field::container_attrs(cx, item));
match item.node { match item.node {
ast::ItemStruct(ref variant_data, _) => { ast::ItemKind::Struct(ref variant_data, _) => {
deserialize_item_struct( deserialize_item_struct(
cx, cx,
builder, builder,
item, item,
impl_generics, impl_generics,
ty, ty,
item.span,
variant_data, variant_data,
) )
} }
ast::ItemEnum(ref enum_def, _) => { ast::ItemKind::Enum(ref enum_def, _) => {
deserialize_item_enum( deserialize_item_enum(
cx, cx,
builder, builder,
@@ -103,7 +113,10 @@ fn deserialize_body(
enum_def, enum_def,
) )
} }
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Deserialize)]") _ => {
cx.span_bug(item.span,
"expected ItemStruct or ItemEnum in #[derive(Deserialize)]")
}
} }
} }
@@ -113,8 +126,9 @@ fn deserialize_item_struct(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
span: Span,
variant_data: &ast::VariantData, variant_data: &ast::VariantData,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
match *variant_data { match *variant_data {
ast::VariantData::Unit(_) => { ast::VariantData::Unit(_) => {
deserialize_unit_struct( deserialize_unit_struct(
@@ -134,7 +148,7 @@ fn deserialize_item_struct(
} }
ast::VariantData::Tuple(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
if fields.iter().any(|field| !field.node.kind.is_unnamed()) { if fields.iter().any(|field| !field.node.kind.is_unnamed()) {
cx.bug("tuple struct has named fields") cx.span_bug(span, "tuple struct has named fields")
} }
deserialize_tuple_struct( deserialize_tuple_struct(
@@ -148,7 +162,7 @@ fn deserialize_item_struct(
} }
ast::VariantData::Struct(ref fields, _) => { ast::VariantData::Struct(ref fields, _) => {
if fields.iter().any(|field| field.node.kind.is_unnamed()) { if fields.iter().any(|field| field.node.kind.is_unnamed()) {
cx.bug("struct has unnamed fields") cx.span_bug(span, "struct has unnamed fields")
} }
deserialize_struct( deserialize_struct(
@@ -170,14 +184,14 @@ fn deserialize_visitor(
trait_generics: &ast::Generics, trait_generics: &ast::Generics,
forward_ty_params: Vec<ast::TyParam>, forward_ty_params: Vec<ast::TyParam>,
forward_tys: Vec<P<ast::Ty>> forward_tys: Vec<P<ast::Ty>>
) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>, ast::Generics) { ) -> Result<(P<ast::Item>, P<ast::Ty>, P<ast::Expr>, ast::Generics), ()> {
if trait_generics.ty_params.is_empty() && forward_tys.is_empty() { if trait_generics.ty_params.is_empty() && forward_tys.is_empty() {
( Ok((
builder.item().tuple_struct("__Visitor").build(), builder.item().tuple_struct("__Visitor").build(),
builder.ty().id("__Visitor"), builder.ty().id("__Visitor"),
builder.expr().id("__Visitor"), builder.expr().id("__Visitor"),
trait_generics.clone(), trait_generics.clone(),
) ))
} else { } else {
let placeholders : Vec<_> = trait_generics.ty_params.iter() let placeholders : Vec<_> = trait_generics.ty_params.iter()
.map(|t| builder.ty().id(t.ident)) .map(|t| builder.ty().id(t.ident))
@@ -187,7 +201,7 @@ fn deserialize_visitor(
ty_params.extend(trait_generics.ty_params.into_vec()); ty_params.extend(trait_generics.ty_params.into_vec());
trait_generics.ty_params = P::from_vec(ty_params); trait_generics.ty_params = P::from_vec(ty_params);
( Ok((
builder.item().tuple_struct("__Visitor") builder.item().tuple_struct("__Visitor")
.generics().with(trait_generics.clone()).build() .generics().with(trait_generics.clone()).build()
.with_tys({ .with_tys({
@@ -225,7 +239,7 @@ fn deserialize_visitor(
}) })
.build(), .build(),
trait_generics, trait_generics,
) ))
} }
} }
@@ -249,10 +263,10 @@ fn deserialize_unit_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
struct __Visitor; struct __Visitor;
impl ::serde::de::Visitor for __Visitor { impl ::serde::de::Visitor for __Visitor {
@@ -275,7 +289,7 @@ fn deserialize_unit_struct(
} }
deserializer.visit_unit_struct($type_name, __Visitor) deserializer.visit_unit_struct($type_name, __Visitor)
}) }))
} }
fn deserialize_newtype_struct( fn deserialize_newtype_struct(
@@ -284,16 +298,15 @@ fn deserialize_newtype_struct(
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
deserialize_visitor( builder,
builder, impl_generics,
impl_generics, vec![deserializer_ty_param(builder)],
vec![deserializer_ty_param(builder)], vec![deserializer_ty_arg(builder)],
vec![deserializer_ty_arg(builder)], ));
);
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
@@ -304,7 +317,7 @@ fn deserialize_newtype_struct(
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_item $visitor_item
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
@@ -327,7 +340,7 @@ fn deserialize_newtype_struct(
} }
deserializer.visit_newtype_struct($type_name, $visitor_expr) deserializer.visit_newtype_struct($type_name, $visitor_expr)
}) }))
} }
fn deserialize_tuple_struct( fn deserialize_tuple_struct(
@@ -337,16 +350,15 @@ fn deserialize_tuple_struct(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
deserialize_visitor( builder,
builder, impl_generics,
impl_generics, vec![deserializer_ty_param(builder)],
vec![deserializer_ty_param(builder)], vec![deserializer_ty_arg(builder)],
vec![deserializer_ty_arg(builder)], ));
);
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
@@ -357,7 +369,7 @@ fn deserialize_tuple_struct(
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_item $visitor_item
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
@@ -372,7 +384,7 @@ fn deserialize_tuple_struct(
} }
deserializer.visit_tuple_struct($type_name, $fields, $visitor_expr) deserializer.visit_tuple_struct($type_name, $fields, $visitor_expr)
}) }))
} }
fn deserialize_seq( fn deserialize_seq(
@@ -381,7 +393,7 @@ fn deserialize_seq(
struct_path: ast::Path, struct_path: ast::Path,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let let_values: Vec<P<ast::Stmt>> = (0 .. fields) let let_values: Vec<ast::Stmt> = (0 .. fields)
.map(|i| { .map(|i| {
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
quote_stmt!(cx, quote_stmt!(cx,
@@ -414,8 +426,8 @@ fn deserialize_struct_as_seq(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let let_values: Vec<P<ast::Stmt>> = (0 .. fields.len()) let let_values: Vec<ast::Stmt> = (0 .. fields.len())
.map(|i| { .map(|i| {
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
quote_stmt!(cx, quote_stmt!(cx,
@@ -437,7 +449,9 @@ fn deserialize_struct_as_seq(
( (
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => name.clone(), ast::NamedField(name, _) => name.clone(),
ast::UnnamedField(_) => cx.bug("struct contains unnamed fields"), ast::UnnamedField(_) => {
cx.span_bug(field.span, "struct contains unnamed fields")
}
}, },
builder.expr().id(format!("__field{}", i)), builder.expr().id(format!("__field{}", i)),
) )
@@ -445,13 +459,13 @@ fn deserialize_struct_as_seq(
) )
.build(); .build();
quote_expr!(cx, { Ok(quote_expr!(cx, {
$let_values $let_values
try!(visitor.end()); try!(visitor.end());
Ok($result) Ok($result)
}) }))
} }
fn deserialize_struct( fn deserialize_struct(
@@ -461,35 +475,35 @@ fn deserialize_struct(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
builder, builder,
&impl_generics, &impl_generics,
vec![deserializer_ty_param(builder)], vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)], vec![deserializer_ty_arg(builder)],
); ));
let type_path = builder.path().id(type_ident).build(); let type_path = builder.path().id(type_ident).build();
let visit_seq_expr = deserialize_struct_as_seq( let visit_seq_expr = try!(deserialize_struct_as_seq(
cx, cx,
builder, builder,
type_path.clone(), type_path.clone(),
fields, fields,
); ));
let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor( let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
cx, cx,
builder, builder,
type_path.clone(), type_path.clone(),
fields, fields,
); ));
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$field_visitor $field_visitor
$visitor_item $visitor_item
@@ -515,7 +529,7 @@ fn deserialize_struct(
$fields_stmt $fields_stmt
deserializer.visit_struct($type_name, FIELDS, $visitor_expr) deserializer.visit_struct($type_name, FIELDS, $visitor_expr)
}) }))
} }
fn deserialize_item_enum( fn deserialize_item_enum(
@@ -525,7 +539,7 @@ fn deserialize_item_enum(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
enum_def: &EnumDef, enum_def: &EnumDef,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
@@ -536,7 +550,7 @@ fn deserialize_item_enum(
enum_def.variants.iter() enum_def.variants.iter()
.map(|variant| { .map(|variant| {
let expr = builder.expr().str(variant.node.name); let expr = builder.expr().str(variant.node.name);
attr::FieldAttrsBuilder::new(builder) attr::FieldAttrsBuilder::new(cx, builder)
.name(expr) .name(expr)
.default() .default()
.build() .build()
@@ -544,7 +558,7 @@ fn deserialize_item_enum(
.collect() .collect()
); );
let variants_expr = builder.expr().addr_of().slice() let variants_expr = builder.expr().ref_().slice()
.with_exprs( .with_exprs(
enum_def.variants.iter() enum_def.variants.iter()
.map(|variant| { .map(|variant| {
@@ -558,35 +572,33 @@ fn deserialize_item_enum(
).unwrap(); ).unwrap();
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
let variant_arms: Vec<_> = enum_def.variants.iter() let mut variant_arms = vec![];
.enumerate() for (i, variant) in enum_def.variants.iter().enumerate() {
.map(|(i, variant)| { let variant_name = builder.pat().enum_()
let variant_name = builder.pat().enum_() .id("__Field").id(format!("__field{}", i)).build()
.id("__Field").id(format!("__field{}", i)).build() .build();
.build();
let expr = deserialize_variant( let expr = try!(deserialize_variant(
cx, cx,
builder,
type_ident,
impl_generics,
ty.clone(),
variant,
);
quote_arm!(cx, $variant_name => { $expr })
})
.collect();
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
type_ident,
impl_generics, impl_generics,
vec![deserializer_ty_param(builder)], ty.clone(),
vec![deserializer_ty_arg(builder)], variant,
); ));
quote_expr!(cx, { let arm = quote_arm!(cx, $variant_name => { $expr });
variant_arms.push(arm);
}
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
builder,
impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
));
Ok(quote_expr!(cx, {
$variant_visitor $variant_visitor
$visitor_item $visitor_item
@@ -606,7 +618,7 @@ fn deserialize_item_enum(
$variants_stmt $variants_stmt
deserializer.visit_enum($type_name, VARIANTS, $visitor_expr) deserializer.visit_enum($type_name, VARIANTS, $visitor_expr)
}) }))
} }
fn deserialize_variant( fn deserialize_variant(
@@ -616,21 +628,21 @@ fn deserialize_variant(
generics: &ast::Generics, generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
variant: &ast::Variant, variant: &ast::Variant,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let variant_ident = variant.node.name; let variant_ident = variant.node.name;
match variant.node.data { match variant.node.data {
ast::VariantData::Unit(_) => { ast::VariantData::Unit(_) => {
quote_expr!(cx, { Ok(quote_expr!(cx, {
try!(visitor.visit_unit()); try!(visitor.visit_unit());
Ok($type_ident::$variant_ident) Ok($type_ident::$variant_ident)
}) }))
} }
ast::VariantData::Tuple(ref args, _) if args.len() == 1 => { ast::VariantData::Tuple(ref args, _) if args.len() == 1 => {
quote_expr!(cx, { Ok(quote_expr!(cx, {
let val = try!(visitor.visit_newtype()); let val = try!(visitor.visit_newtype());
Ok($type_ident::$variant_ident(val)) Ok($type_ident::$variant_ident(val))
}) }))
} }
ast::VariantData::Tuple(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
deserialize_tuple_variant( deserialize_tuple_variant(
@@ -665,16 +677,15 @@ fn deserialize_tuple_variant(
generics: &ast::Generics, generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &generics.where_clause; let where_clause = &generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
deserialize_visitor( builder,
builder, generics,
generics, vec![deserializer_ty_param(builder)],
vec![deserializer_ty_param(builder)], vec![deserializer_ty_arg(builder)],
vec![deserializer_ty_arg(builder)], ));
);
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
@@ -683,7 +694,7 @@ fn deserialize_tuple_variant(
fields, fields,
); );
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_item $visitor_item
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
@@ -697,7 +708,7 @@ fn deserialize_tuple_variant(
} }
visitor.visit_tuple($fields, $visitor_expr) visitor.visit_tuple($fields, $visitor_expr)
}) }))
} }
fn deserialize_struct_variant( fn deserialize_struct_variant(
@@ -708,7 +719,7 @@ fn deserialize_struct_variant(
generics: &ast::Generics, generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let where_clause = &generics.where_clause; let where_clause = &generics.where_clause;
let type_path = builder.path() let type_path = builder.path()
@@ -716,29 +727,28 @@ fn deserialize_struct_variant(
.id(variant_ident) .id(variant_ident)
.build(); .build();
let visit_seq_expr = deserialize_struct_as_seq( let visit_seq_expr = try!(deserialize_struct_as_seq(
cx, cx,
builder, builder,
type_path.clone(), type_path.clone(),
fields, fields,
); ));
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor( let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
cx, cx,
builder, builder,
type_path, type_path,
fields, fields,
); ));
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
deserialize_visitor( builder,
builder, generics,
generics, vec![deserializer_ty_param(builder)],
vec![deserializer_ty_param(builder)], vec![deserializer_ty_arg(builder)],
vec![deserializer_ty_arg(builder)], ));
);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$field_visitor $field_visitor
$visitor_item $visitor_item
@@ -764,7 +774,7 @@ fn deserialize_struct_variant(
$fields_stmt $fields_stmt
visitor.visit_struct(FIELDS, $visitor_expr) visitor.visit_struct(FIELDS, $visitor_expr)
}) }))
} }
fn deserialize_field_visitor( fn deserialize_field_visitor(
@@ -907,7 +917,7 @@ fn deserialize_field_visitor(
} }
} }
deserializer.visit(__FieldVisitor::<D>{ phantom: PhantomData }) deserializer.visit_struct_field(__FieldVisitor::<D>{ phantom: PhantomData })
} }
} }
).unwrap(); ).unwrap();
@@ -920,27 +930,29 @@ fn deserialize_struct_visitor(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> (Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>) { ) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), ()> {
let field_visitor = deserialize_field_visitor( let field_visitor = deserialize_field_visitor(
cx, cx,
builder, builder,
field::struct_field_attrs(cx, builder, fields), try!(field::struct_field_attrs(cx, builder, fields)),
); );
let visit_map_expr = deserialize_map( let visit_map_expr = try!(deserialize_map(
cx, cx,
builder, builder,
struct_path, struct_path,
fields, fields,
); ));
let fields_expr = builder.expr().addr_of().slice() let fields_expr = builder.expr().ref_().slice()
.with_exprs( .with_exprs(
fields.iter() fields.iter()
.map(|field| { .map(|field| {
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => builder.expr().str(name), ast::NamedField(name, _) => builder.expr().str(name),
ast::UnnamedField(_) => panic!("struct contains unnamed fields"), ast::UnnamedField(_) => {
cx.span_bug(field.span, "struct contains unnamed fields")
}
} }
}) })
) )
@@ -950,7 +962,7 @@ fn deserialize_struct_visitor(
const FIELDS: &'static [&'static str] = $fields_expr; const FIELDS: &'static [&'static str] = $fields_expr;
).unwrap(); ).unwrap();
(field_visitor, fields_stmt, visit_map_expr) Ok((field_visitor, fields_stmt, visit_map_expr))
} }
fn deserialize_map( fn deserialize_map(
@@ -958,14 +970,14 @@ fn deserialize_map(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
// Create the field names for the fields. // Create the field names for the fields.
let field_names: Vec<ast::Ident> = (0 .. fields.len()) let field_names: Vec<ast::Ident> = (0 .. fields.len())
.map(|i| builder.id(format!("__field{}", i))) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
// Declare each field. // Declare each field.
let let_values: Vec<P<ast::Stmt>> = field_names.iter() let let_values: Vec<ast::Stmt> = field_names.iter()
.map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap()) .map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap())
.collect(); .collect();
@@ -980,8 +992,10 @@ fn deserialize_map(
}) })
.collect(); .collect();
let extract_values: Vec<P<ast::Stmt>> = field_names.iter() let field_attrs = try!(field::struct_field_attrs(cx, builder, fields));
.zip(field::struct_field_attrs(cx, builder, fields).iter())
let extract_values: Vec<ast::Stmt> = field_names.iter()
.zip(field_attrs.iter())
.map(|(field_name, field_attr)| { .map(|(field_name, field_attr)| {
let missing_expr = if field_attr.use_default() { let missing_expr = if field_attr.use_default() {
quote_expr!(cx, ::std::default::Default::default()) quote_expr!(cx, ::std::default::Default::default())
@@ -1024,7 +1038,9 @@ fn deserialize_map(
( (
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => name.clone(), ast::NamedField(name, _) => name.clone(),
ast::UnnamedField(_) => panic!("struct contains unnamed fields"), ast::UnnamedField(_) => {
cx.span_bug(field.span, "struct contains unnamed fields")
}
}, },
builder.expr().id(field_name), builder.expr().id(field_name),
) )
@@ -1032,7 +1048,7 @@ fn deserialize_map(
) )
.build(); .build();
quote_expr!(cx, { Ok(quote_expr!(cx, {
$let_values $let_values
while let Some(key) = try!(visitor.visit_key()) { while let Some(key) = try!(visitor.visit_key()) {
@@ -1046,5 +1062,5 @@ fn deserialize_map(
try!(visitor.end()); try!(visitor.end());
Ok($result) Ok($result)
}) }))
} }
+21 -8
View File
@@ -2,16 +2,29 @@ use syntax::ast;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use aster; use aster;
use attr::{FieldAttrs, FieldAttrsBuilder}; use attr;
pub fn struct_field_attrs( pub fn struct_field_attrs(
_cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> Vec<FieldAttrs> { ) -> Result<Vec<attr::FieldAttrs>, ()> {
fields.iter() let mut attrs = vec![];
.map(|field| { for field in fields {
FieldAttrsBuilder::new(builder).field(field).build() let builder = attr::FieldAttrsBuilder::new(cx, builder);
}) let builder = try!(builder.field(field));
.collect() let attr = builder.build();
attrs.push(attr);
}
Ok(attrs)
}
pub fn container_attrs(
cx: &ExtCtxt,
container: &ast::Item,
) -> Result<attr::ContainerAttrs, ()> {
let builder = attr::ContainerAttrsBuilder::new(cx);
let builder = try!(builder.attrs(container.attrs()));
Ok(builder.build())
} }
+17 -9
View File
@@ -1,3 +1,6 @@
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] #![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))] #![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]
@@ -16,6 +19,9 @@ extern crate syntax;
#[cfg(not(feature = "with-syntex"))] #[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin; extern crate rustc_plugin;
#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;
#[cfg(feature = "with-syntex")] #[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs")); include!(concat!(env!("OUT_DIR"), "/lib.rs"));
@@ -26,14 +32,6 @@ include!("lib.rs.in");
pub fn register(reg: &mut syntex::Registry) { pub fn register(reg: &mut syntex::Registry) {
use syntax::{ast, fold}; use syntax::{ast, fold};
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);
/// Strip the serde attributes from the crate. /// Strip the serde attributes from the crate.
#[cfg(feature = "with-syntex")] #[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate { fn strip_attributes(krate: ast::Crate) -> ast::Crate {
@@ -43,7 +41,7 @@ pub fn register(reg: &mut 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 { match attr.node.value.node {
ast::MetaList(ref n, _) if n == &"serde" => { return None; } ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
_ => {} _ => {}
} }
@@ -57,6 +55,14 @@ pub fn register(reg: &mut syntex::Registry) {
fold::Folder::fold_crate(&mut StripAttributeFolder, krate) fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
} }
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);
} }
#[cfg(not(feature = "with-syntex"))] #[cfg(not(feature = "with-syntex"))]
@@ -70,4 +76,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
syntax::parse::token::intern("derive_Deserialize"), syntax::parse::token::intern("derive_Deserialize"),
syntax::ext::base::MultiDecorator( syntax::ext::base::MultiDecorator(
Box::new(de::expand_derive_deserialize))); Box::new(de::expand_derive_deserialize)));
reg.register_attribute("serde".to_owned(), AttributeType::Normal);
} }
+97 -71
View File
@@ -11,7 +11,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::ptr::P; use syntax::ptr::P;
use field::struct_field_attrs; use field;
pub fn expand_derive_serialize( pub fn expand_derive_serialize(
cx: &mut ExtCtxt, cx: &mut ExtCtxt,
@@ -25,7 +25,7 @@ pub fn expand_derive_serialize(
_ => { _ => {
cx.span_err( cx.span_err(
meta_item.span, meta_item.span,
"`derive` may only be applied to structs and enums"); "`#[derive(Serialize)]` may only be applied to structs and enums");
return; return;
} }
}; };
@@ -33,9 +33,14 @@ pub fn expand_derive_serialize(
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let generics = match item.node { let generics = match item.node {
ast::ItemStruct(_, ref generics) => generics, ast::ItemKind::Struct(_, ref generics) => generics,
ast::ItemEnum(_, ref generics) => generics, ast::ItemKind::Enum(_, ref generics) => generics,
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Serialize)]") _ => {
cx.span_err(
meta_item.span,
"`#[derive(Serialize)]` may only be applied to structs and enums");
return;
}
}; };
let impl_generics = builder.from_generics(generics.clone()) let impl_generics = builder.from_generics(generics.clone())
@@ -48,13 +53,13 @@ pub fn expand_derive_serialize(
.segment(item.ident).with_generics(impl_generics.clone()).build() .segment(item.ident).with_generics(impl_generics.clone()).build()
.build(); .build();
let body = serialize_body( let body = match serialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
cx, Ok(body) => body,
&builder, Err(()) => {
&item, // An error occured, but it should have been reported already.
&impl_generics, return;
ty.clone(), }
); };
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@@ -77,19 +82,24 @@ fn serialize_body(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
// Note: While we don't have any container attributes, we still want to try to
// parse them so we can report a proper error if we get passed an unknown attribute.
let _ = try!(field::container_attrs(cx, item));
match item.node { match item.node {
ast::ItemStruct(ref variant_data, _) => { ast::ItemKind::Struct(ref variant_data, _) => {
serialize_item_struct( serialize_item_struct(
cx, cx,
builder, builder,
item, item,
impl_generics, impl_generics,
ty, ty,
item.span,
variant_data, variant_data,
) )
} }
ast::ItemEnum(ref enum_def, _) => { ast::ItemKind::Enum(ref enum_def, _) => {
serialize_item_enum( serialize_item_enum(
cx, cx,
builder, builder,
@@ -99,7 +109,10 @@ fn serialize_body(
enum_def, enum_def,
) )
} }
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Serialize)]") _ => {
cx.span_bug(item.span,
"expected ItemStruct or ItemEnum in #[derive(Serialize)]");
}
} }
} }
@@ -109,8 +122,9 @@ fn serialize_item_struct(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
span: Span,
variant_data: &ast::VariantData, variant_data: &ast::VariantData,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
match *variant_data { match *variant_data {
ast::VariantData::Unit(_) => { ast::VariantData::Unit(_) => {
serialize_unit_struct( serialize_unit_struct(
@@ -128,7 +142,7 @@ fn serialize_item_struct(
} }
ast::VariantData::Tuple(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
if fields.iter().any(|field| !field.node.kind.is_unnamed()) { if fields.iter().any(|field| !field.node.kind.is_unnamed()) {
cx.bug("tuple struct has named fields") cx.span_bug(span, "tuple struct has named fields")
} }
serialize_tuple_struct( serialize_tuple_struct(
@@ -142,7 +156,7 @@ fn serialize_item_struct(
} }
ast::VariantData::Struct(ref fields, _) => { ast::VariantData::Struct(ref fields, _) => {
if fields.iter().any(|field| field.node.kind.is_unnamed()) { if fields.iter().any(|field| field.node.kind.is_unnamed()) {
cx.bug("struct has unnamed fields") cx.span_bug(span, "struct has unnamed fields")
} }
serialize_struct( serialize_struct(
@@ -161,20 +175,24 @@ fn serialize_unit_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident type_ident: Ident
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, serializer.visit_unit_struct($type_name)) Ok(quote_expr!(cx,
serializer.visit_unit_struct($type_name)
))
} }
fn serialize_newtype_struct( fn serialize_newtype_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident type_ident: Ident
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, serializer.visit_newtype_struct($type_name, &self.0)) Ok(quote_expr!(cx,
serializer.visit_newtype_struct($type_name, &self.0)
))
} }
fn serialize_tuple_struct( fn serialize_tuple_struct(
@@ -184,7 +202,7 @@ fn serialize_tuple_struct(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor( let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx, cx,
builder, builder,
@@ -199,7 +217,7 @@ fn serialize_tuple_struct(
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_struct $visitor_struct
$visitor_impl $visitor_impl
serializer.visit_tuple_struct($type_name, Visitor { serializer.visit_tuple_struct($type_name, Visitor {
@@ -207,7 +225,7 @@ fn serialize_tuple_struct(
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData::<&$ty>, _structure_ty: ::std::marker::PhantomData::<&$ty>,
}) })
}) }))
} }
fn serialize_struct( fn serialize_struct(
@@ -217,8 +235,13 @@ fn serialize_struct(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let value_exprs = fields.iter().map(|field| {
let name = field.node.ident().expect("struct has unnamed field");
quote_expr!(cx, &self.value.$name)
});
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
cx, cx,
builder, builder,
ty.clone(), ty.clone(),
@@ -228,15 +251,12 @@ fn serialize_struct(
.build_ty(ty.clone()), .build_ty(ty.clone()),
fields, fields,
impl_generics, impl_generics,
fields.iter().map(|field| { value_exprs,
let name = field.node.ident().expect("struct has unnamed field"); ));
quote_expr!(cx, &self.value.$name)
})
);
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_struct $visitor_struct
$visitor_impl $visitor_impl
serializer.visit_struct($type_name, Visitor { serializer.visit_struct($type_name, Visitor {
@@ -244,7 +264,7 @@ fn serialize_struct(
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData::<&$ty>, _structure_ty: ::std::marker::PhantomData::<&$ty>,
}) })
}) }))
} }
fn serialize_item_enum( fn serialize_item_enum(
@@ -254,27 +274,28 @@ fn serialize_item_enum(
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
enum_def: &ast::EnumDef, enum_def: &ast::EnumDef,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let arms: Vec<ast::Arm> = enum_def.variants.iter() let mut arms = vec![];
.enumerate()
.map(|(variant_index, variant)| {
serialize_variant(
cx,
builder,
type_ident,
impl_generics,
ty.clone(),
variant,
variant_index,
)
})
.collect();
quote_expr!(cx, for (variant_index, variant) in enum_def.variants.iter().enumerate() {
let arm = try!(serialize_variant(
cx,
builder,
type_ident,
impl_generics,
ty.clone(),
variant,
variant_index,
));
arms.push(arm);
}
Ok(quote_expr!(cx,
match *self { match *self {
$arms $arms
} }
) ))
} }
fn serialize_variant( fn serialize_variant(
@@ -285,7 +306,7 @@ fn serialize_variant(
ty: P<ast::Ty>, ty: P<ast::Ty>,
variant: &ast::Variant, variant: &ast::Variant,
variant_index: usize, variant_index: usize,
) -> ast::Arm { ) -> Result<ast::Arm, ()> {
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
let variant_ident = variant.node.name; let variant_ident = variant.node.name;
let variant_name = builder.expr().str(variant_ident); let variant_name = builder.expr().str(variant_ident);
@@ -296,7 +317,7 @@ fn serialize_variant(
.id(type_ident).id(variant_ident).build() .id(type_ident).id(variant_ident).build()
.build(); .build();
quote_arm!(cx, Ok(quote_arm!(cx,
$pat => { $pat => {
::serde::ser::Serializer::visit_unit_variant( ::serde::ser::Serializer::visit_unit_variant(
serializer, serializer,
@@ -305,7 +326,7 @@ fn serialize_variant(
$variant_name, $variant_name,
) )
} }
) ))
}, },
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
let field = builder.id("__simple_value"); let field = builder.id("__simple_value");
@@ -314,7 +335,8 @@ fn serialize_variant(
.id(type_ident).id(variant_ident).build() .id(type_ident).id(variant_ident).build()
.with_pats(Some(field).into_iter()) .with_pats(Some(field).into_iter())
.build(); .build();
quote_arm!(cx,
Ok(quote_arm!(cx,
$pat => { $pat => {
::serde::ser::Serializer::visit_newtype_variant( ::serde::ser::Serializer::visit_newtype_variant(
serializer, serializer,
@@ -324,7 +346,7 @@ fn serialize_variant(
__simple_value, __simple_value,
) )
} }
) ))
}, },
ast::VariantData::Tuple(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
let field_names: Vec<ast::Ident> = (0 .. fields.len()) let field_names: Vec<ast::Ident> = (0 .. fields.len())
@@ -351,7 +373,9 @@ fn serialize_variant(
field_names, field_names,
); );
quote_arm!(cx, $pat => { $expr }) Ok(quote_arm!(cx,
$pat => { $expr }
))
} }
ast::VariantData::Struct(ref fields, _) => { ast::VariantData::Struct(ref fields, _) => {
let field_names: Vec<_> = (0 .. fields.len()) let field_names: Vec<_> = (0 .. fields.len())
@@ -367,7 +391,7 @@ fn serialize_variant(
let name = match field.node.kind { let name = match field.node.kind {
ast::NamedField(name, _) => name, ast::NamedField(name, _) => name,
ast::UnnamedField(_) => { ast::UnnamedField(_) => {
cx.bug("struct variant has unnamed fields") cx.span_bug(field.span, "struct variant has unnamed fields")
} }
}; };
@@ -376,7 +400,7 @@ fn serialize_variant(
) )
.build(); .build();
let expr = serialize_struct_variant( let expr = try!(serialize_struct_variant(
cx, cx,
builder, builder,
type_name, type_name,
@@ -386,9 +410,11 @@ fn serialize_variant(
ty, ty,
fields, fields,
field_names, field_names,
); ));
quote_arm!(cx, $pat => { $expr }) Ok(quote_arm!(cx,
$pat => { $expr }
))
} }
} }
} }
@@ -453,7 +479,7 @@ fn serialize_struct_variant(
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
field_names: Vec<Ident>, field_names: Vec<Ident>,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, ()> {
let value_ty = builder.ty().tuple() let value_ty = builder.ty().tuple()
.with_tys( .with_tys(
fields.iter().map(|field| { fields.iter().map(|field| {
@@ -473,7 +499,7 @@ fn serialize_struct_variant(
) )
.build(); .build();
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
cx, cx,
builder, builder,
structure_ty.clone(), structure_ty.clone(),
@@ -485,9 +511,9 @@ fn serialize_struct_variant(
.tup_field(i) .tup_field(i)
.field("value").self_() .field("value").self_()
}) })
); ));
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_struct $visitor_struct
$visitor_impl $visitor_impl
serializer.visit_struct_variant($type_name, $variant_index, $variant_name, Visitor { serializer.visit_struct_variant($type_name, $variant_index, $variant_name, Visitor {
@@ -495,7 +521,7 @@ fn serialize_struct_variant(
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>, _structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
}) })
}) }))
} }
fn serialize_tuple_struct_visitor( fn serialize_tuple_struct_visitor(
@@ -573,12 +599,12 @@ fn serialize_struct_visitor<I>(
fields: &[ast::StructField], fields: &[ast::StructField],
generics: &ast::Generics, generics: &ast::Generics,
value_exprs: I, value_exprs: I,
) -> (P<ast::Item>, P<ast::Item>) ) -> Result<(P<ast::Item>, P<ast::Item>), ()>
where I: Iterator<Item=P<ast::Expr>>, where I: Iterator<Item=P<ast::Expr>>,
{ {
let value_exprs = value_exprs.collect::<Vec<_>>(); let value_exprs = value_exprs.collect::<Vec<_>>();
let field_attrs = struct_field_attrs(cx, builder, fields); let field_attrs = try!(field::struct_field_attrs(cx, builder, fields));
let arms: Vec<ast::Arm> = field_attrs.iter() let arms: Vec<ast::Arm> = field_attrs.iter()
.zip(value_exprs.iter()) .zip(value_exprs.iter())
@@ -641,7 +667,7 @@ fn serialize_struct_visitor<I>(
}) })
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr)); .fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
( Ok((
quote_item!(cx, quote_item!(cx,
struct Visitor $visitor_impl_generics $where_clause { struct Visitor $visitor_impl_generics $where_clause {
state: usize, state: usize,
@@ -673,5 +699,5 @@ fn serialize_struct_visitor<I>(
} }
} }
).unwrap(), ).unwrap(),
) ))
} }
+16 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_macros" name = "serde_macros"
version = "0.6.6" version = "0.6.13"
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"
@@ -12,10 +12,23 @@ keywords = ["serde", "serialization"]
name = "serde_macros" name = "serde_macros"
plugin = true plugin = true
[features]
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
[dependencies] [dependencies]
serde_codegen = { version = "*", path = "../serde_codegen", default-features = false, features = ["nightly"] } clippy = { version = "^0.0.41", optional = true }
serde_codegen = { version = "^0.6.13", path = "../serde_codegen", default-features = false, features = ["nightly"] }
[dev-dependencies] [dev-dependencies]
compiletest_rs = "^0.0.11"
num = "^0.1.27" num = "^0.1.27"
rustc-serialize = "^0.3.16" rustc-serialize = "^0.3.16"
serde = { version = "*", path = "../serde", features = ["nightly", "num-impls"] } serde = { version = "^0.6.13", path = "../serde", features = ["num-impls"] }
[[test]]
name = "test"
path = "tests/test.rs"
[[bench]]
name = "bench"
path = "benches/bench.rs"
+1
View File
@@ -1,4 +1,5 @@
#![feature(custom_attribute, custom_derive, plugin, test)] #![feature(custom_attribute, custom_derive, plugin, test)]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![plugin(serde_macros)] #![plugin(serde_macros)]
extern crate num; extern crate num;
+2
View File
@@ -1,4 +1,6 @@
#![feature(plugin_registrar, rustc_private)] #![feature(plugin_registrar, rustc_private)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
extern crate serde_codegen; extern crate serde_codegen;
extern crate rustc_plugin; extern crate rustc_plugin;
@@ -0,0 +1,30 @@
#![feature(custom_attribute, custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate serde;
#[derive(Serialize)]
#[serde(abc="xyz")] //~ unknown serde container attribute `abc = "xyz"`
struct Foo {
x: u32,
}
#[derive(Deserialize)]
#[serde(abc="xyz")] //~ unknown serde container attribute `abc = "xyz"`
struct Foo {
x: u32,
}
#[derive(Serialize)]
struct Foo {
#[serde(abc="xyz")] //~ unknown serde field attribute `abc = "xyz"`
x: u32,
}
#[derive(Deserialize)]
struct Foo {
#[serde(abc="xyz")] //~ unknown serde field attribute `abc = "xyz"`
x: u32,
}
fn main() { }
+25
View File
@@ -0,0 +1,25 @@
extern crate compiletest_rs as compiletest;
use std::path::PathBuf;
use std::env::var;
fn run_mode(mode: &'static str) {
let mut config = compiletest::default_config();
let cfg_mode = mode.parse().ok().expect("Invalid mode");
config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());
if let Ok(name) = var::<&str>("TESTNAME") {
let s : String = name.to_owned();
config.filter = Some(s)
}
config.mode = cfg_mode;
config.src_base = PathBuf::from(format!("tests/{}", mode));
compiletest::run_tests(&config);
}
#[test]
fn compile_test() {
run_mode("compile-fail");
}
+2
View File
@@ -6,3 +6,5 @@ extern crate serde;
extern crate test; extern crate test;
include!("../../serde_tests/tests/test.rs.in"); include!("../../serde_tests/tests/test.rs.in");
mod compile_tests;
+12 -6
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_tests" name = "serde_tests"
version = "0.6.2" version = "0.6.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 = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
@@ -10,16 +10,22 @@ readme = "README.md"
keywords = ["serialization"] keywords = ["serialization"]
build = "build.rs" build = "build.rs"
[features]
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
[build-dependencies] [build-dependencies]
syntex = { version = "^0.26.0" } syntex = { version = "^0.28.0" }
syntex_syntax = { version = "^0.26.0" } syntex_syntax = { version = "^0.28.0" }
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] } serde_codegen = { version = "^0.6.13", path = "../serde_codegen", features = ["with-syntex"] }
[dev-dependencies] [dev-dependencies]
num = "^0.1.27" num = "^0.1.26"
rustc-serialize = "^0.3.16" rustc-serialize = "^0.3.16"
serde = { version = "*", path = "../serde", features = ["num-impls"] } serde = { version = "*", path = "../serde", features = ["num-impls"] }
syntex = "^0.26.0" syntex = "^0.28.0"
[dependencies]
clippy = { version = "^0.0.41", optional = true }
[[test]] [[test]]
name = "test" name = "test"
+2
View File
@@ -1,4 +1,6 @@
#![feature(test)] #![feature(test)]
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "nightly", plugin(clippy))]
extern crate num; extern crate num;
extern crate rustc_serialize; extern crate rustc_serialize;
+2 -2
View File
@@ -415,7 +415,7 @@ fn bench_decoder_dog(b: &mut Bencher) {
#[bench] #[bench]
fn bench_decoder_frog(b: &mut Bencher) { fn bench_decoder_frog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Animal::Frog("Henry".to_string(), 349); let animal = Animal::Frog("Henry".to_owned(), 349);
let mut d = decoder::AnimalDecoder::new(animal.clone()); let mut d = decoder::AnimalDecoder::new(animal.clone());
let value: Animal = Decodable::decode(&mut d).unwrap(); let value: Animal = Decodable::decode(&mut d).unwrap();
@@ -439,7 +439,7 @@ fn bench_deserializer_dog(b: &mut Bencher) {
#[bench] #[bench]
fn bench_deserializer_frog(b: &mut Bencher) { fn bench_deserializer_frog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Animal::Frog("Henry".to_string(), 349); let animal = Animal::Frog("Henry".to_owned(), 349);
let mut d = deserializer::AnimalDeserializer::new(animal.clone()); let mut d = deserializer::AnimalDeserializer::new(animal.clone());
let value: Animal = Deserialize::deserialize(&mut d).unwrap(); let value: Animal = Deserialize::deserialize(&mut d).unwrap();
+4 -4
View File
@@ -399,7 +399,7 @@ fn bench_decoder_000(b: &mut Bencher) {
fn bench_decoder_003(b: &mut Bencher) { fn bench_decoder_003(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut m: HashMap<String, isize> = HashMap::new(); let mut m: HashMap<String, isize> = HashMap::new();
for i in (0 .. 3) { for i in 0 .. 3 {
m.insert(i.to_string(), i); m.insert(i.to_string(), i);
} }
run_decoder(decoder::IsizeDecoder::new(m.clone()), m) run_decoder(decoder::IsizeDecoder::new(m.clone()), m)
@@ -410,7 +410,7 @@ fn bench_decoder_003(b: &mut Bencher) {
fn bench_decoder_100(b: &mut Bencher) { fn bench_decoder_100(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut m: HashMap<String, isize> = HashMap::new(); let mut m: HashMap<String, isize> = HashMap::new();
for i in (0 .. 100) { for i in 0 .. 100 {
m.insert(i.to_string(), i); m.insert(i.to_string(), i);
} }
run_decoder(decoder::IsizeDecoder::new(m.clone()), m) run_decoder(decoder::IsizeDecoder::new(m.clone()), m)
@@ -439,7 +439,7 @@ fn bench_deserializer_000(b: &mut Bencher) {
fn bench_deserializer_003(b: &mut Bencher) { fn bench_deserializer_003(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut m: HashMap<String, isize> = HashMap::new(); let mut m: HashMap<String, isize> = HashMap::new();
for i in (0 .. 3) { for i in 0 .. 3 {
m.insert(i.to_string(), i); m.insert(i.to_string(), i);
} }
run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m) run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m)
@@ -450,7 +450,7 @@ fn bench_deserializer_003(b: &mut Bencher) {
fn bench_deserializer_100(b: &mut Bencher) { fn bench_deserializer_100(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut m: HashMap<String, isize> = HashMap::new(); let mut m: HashMap<String, isize> = HashMap::new();
for i in (0 .. 100) { for i in 0 .. 100 {
m.insert(i.to_string(), i); m.insert(i.to_string(), i);
} }
run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m) run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m)
+11 -11
View File
@@ -614,7 +614,7 @@ mod deserializer {
fn bench_decoder_0_0(b: &mut Bencher) { fn bench_decoder_0_0(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("abc".to_string(), Some('c')); map.insert("abc".to_owned(), Some('c'));
let outer = Outer { let outer = Outer {
inner: vec!(), inner: vec!(),
@@ -653,11 +653,11 @@ fn bench_decoder_1_0(b: &mut Bencher) {
fn bench_decoder_1_5(b: &mut Bencher) { fn bench_decoder_1_5(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("1".to_string(), Some('a')); map.insert("1".to_owned(), Some('a'));
map.insert("2".to_string(), None); map.insert("2".to_owned(), None);
map.insert("3".to_string(), Some('b')); map.insert("3".to_owned(), Some('b'));
map.insert("4".to_string(), None); map.insert("4".to_owned(), None);
map.insert("5".to_string(), Some('c')); map.insert("5".to_owned(), Some('c'));
let outer = Outer { let outer = Outer {
inner: vec!( inner: vec!(
@@ -716,11 +716,11 @@ fn bench_deserializer_1_0(b: &mut Bencher) {
fn bench_deserializer_1_5(b: &mut Bencher) { fn bench_deserializer_1_5(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("1".to_string(), Some('a')); map.insert("1".to_owned(), Some('a'));
map.insert("2".to_string(), None); map.insert("2".to_owned(), None);
map.insert("3".to_string(), Some('b')); map.insert("3".to_owned(), Some('b'));
map.insert("4".to_string(), None); map.insert("4".to_owned(), None);
map.insert("5".to_string(), Some('c')); map.insert("5".to_owned(), Some('c'));
let outer = Outer { let outer = Outer {
inner: vec!( inner: vec!(
+3
View File
@@ -1,3 +1,6 @@
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "nightly", plugin(clippy))]
extern crate num; extern crate num;
extern crate serde; extern crate serde;
+10 -4
View File
@@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::path::PathBuf;
use num::FromPrimitive; use num::FromPrimitive;
use num::bigint::{BigInt, BigUint}; use num::bigint::{BigInt, BigUint};
@@ -95,12 +96,12 @@ declare_tests! {
test_char { test_char {
'a' => vec![Token::Char('a')], 'a' => vec![Token::Char('a')],
'a' => vec![Token::Str("a")], 'a' => vec![Token::Str("a")],
'a' => vec![Token::String("a".to_string())], 'a' => vec![Token::String("a".to_owned())],
} }
test_string { test_string {
"abc".to_string() => vec![Token::Str("abc")], "abc".to_owned() => vec![Token::Str("abc")],
"abc".to_string() => vec![Token::String("abc".to_string())], "abc".to_owned() => vec![Token::String("abc".to_owned())],
"a".to_string() => vec![Token::Char('a')], "a".to_owned() => vec![Token::Char('a')],
} }
test_option { test_option {
None::<i32> => vec![Token::Unit], None::<i32> => vec![Token::Unit],
@@ -589,4 +590,9 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_path_buf {
PathBuf::from("/usr/local/lib") => vec![
Token::String("/usr/local/lib".to_owned()),
],
}
} }
+12 -1
View File
@@ -1,4 +1,5 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use num::FromPrimitive; use num::FromPrimitive;
use num::bigint::{BigInt, BigUint}; use num::bigint::{BigInt, BigUint};
@@ -63,7 +64,7 @@ declare_ser_tests! {
} }
test_str { test_str {
"abc" => &[Token::Str("abc")], "abc" => &[Token::Str("abc")],
"abc".to_string() => &[Token::Str("abc")], "abc".to_owned() => &[Token::Str("abc")],
} }
test_option { test_option {
None::<i32> => &[Token::Option(false)], None::<i32> => &[Token::Option(false)],
@@ -293,4 +294,14 @@ declare_ser_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_path {
Path::new("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),
],
}
test_path_buf {
PathBuf::from("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),
],
}
} }
+1 -2
View File
@@ -325,7 +325,7 @@ impl de::Error for Error {
fn end_of_stream() -> Error { Error::EndOfStreamError } fn end_of_stream() -> Error { Error::EndOfStreamError }
fn unknown_field(field: &str) -> Error { fn unknown_field(field: &str) -> Error {
Error::UnknownFieldError(field.to_string()) Error::UnknownFieldError(field.to_owned())
} }
fn missing_field(field: &'static str) -> Error { fn missing_field(field: &'static str) -> Error {
@@ -379,7 +379,6 @@ impl<I> de::Deserializer for Deserializer<I>
fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, Error> fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
where V: de::Visitor, where V: de::Visitor,
{ {
println!("visit {:?}", self.tokens.peek());
match self.tokens.next() { match self.tokens.next() {
Some(Token::Bool(v)) => visitor.visit_bool(v), Some(Token::Bool(v)) => visitor.visit_bool(v),
Some(Token::Isize(v)) => visitor.visit_isize(v), Some(Token::Isize(v)) => visitor.visit_isize(v),