mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 02:28:00 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6a66a5537 | |||
| fd5ab8c5c8 | |||
| 39fa78e2ec | |||
| e18416ac7f | |||
| b63cc13f3a | |||
| 74b230c183 | |||
| 064241f03c | |||
| 32163cd53b | |||
| 3a5aa00262 | |||
| 7a3e3a61f4 | |||
| 517c2f79b7 | |||
| 3cde6fa333 | |||
| da7bb8e109 | |||
| 718822449f | |||
| 43624e8e7f | |||
| 4507eaec5b | |||
| b3212f4c2b | |||
| 6d25fc9dbb | |||
| a5d0703e44 | |||
| 0a32cea26e | |||
| da4e37d3f5 | |||
| 3f9cbc157a | |||
| a51f930101 | |||
| 77edd8e544 | |||
| 8087b7cec6 | |||
| 8df841f048 | |||
| bfa2b69193 | |||
| fbcf905c9f | |||
| 979a4bcd88 | |||
| 342ea25290 | |||
| 8d8f17982a | |||
| dd3233ac85 | |||
| 9b57f60c2a | |||
| 8038832a79 | |||
| 072ff149f5 |
+4
-2
@@ -22,9 +22,11 @@ script:
|
||||
- |
|
||||
(cd serde && travis-cargo build) &&
|
||||
(cd serde && travis-cargo test) &&
|
||||
(cd serde && travis-cargo --only nightly test -- --features nightly-testing) &&
|
||||
(cd serde_tests && travis-cargo test) &&
|
||||
(cd serde_macros && travis-cargo --only nightly test) &&
|
||||
(cd serde_macros && travis-cargo --only nightly bench) &&
|
||||
(cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing) &&
|
||||
(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_codegen && travis-cargo --only stable doc)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
```
|
||||
@@ -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
|
||||
===========
|
||||
|
||||
|
||||
+7
-6
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.6.6"
|
||||
version = "0.6.14"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -9,12 +9,13 @@ documentation = "https://serde-rs.github.io/serde/serde/serde/index.html"
|
||||
readme = "../README.md"
|
||||
keywords = ["serde", "serialization"]
|
||||
|
||||
[dependencies]
|
||||
num = "^0.1.27"
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
num-impls = ["num-bigint", "num-complex", "num-rational"]
|
||||
nightly-testing = ["clippy"]
|
||||
num-bigint = ["num/bigint"]
|
||||
num-complex = ["num/complex"]
|
||||
num-impls = ["num-bigint", "num-complex", "num-rational"]
|
||||
num-rational = ["num/rational"]
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
num = { version = "^0.1.27", default-features = false }
|
||||
|
||||
+14
-5
@@ -154,7 +154,9 @@ impl<
|
||||
fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
|
||||
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>
|
||||
where E: Error,
|
||||
{
|
||||
Ok(v.to_string())
|
||||
Ok(v.to_owned())
|
||||
}
|
||||
|
||||
fn visit_string<E>(&mut self, v: String) -> Result<String, E>
|
||||
@@ -247,12 +249,12 @@ impl Visitor for StringVisitor {
|
||||
where E: Error,
|
||||
{
|
||||
match str::from_utf8(v) {
|
||||
Ok(s) => Ok(s.to_string()),
|
||||
Ok(s) => Ok(s.to_owned()),
|
||||
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,
|
||||
{
|
||||
match String::from_utf8(v) {
|
||||
@@ -281,6 +283,13 @@ impl<
|
||||
> Visitor for OptionVisitor<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(&mut self) -> Result<Option<T>, E>
|
||||
where E: Error,
|
||||
{
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none<E>(&mut self) -> Result<Option<T>, E>
|
||||
where E: Error,
|
||||
@@ -753,7 +762,7 @@ impl Deserialize for path::PathBuf {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error>
|
||||
where D: Deserializer,
|
||||
{
|
||||
deserializer.visit(PathBufVisitor)
|
||||
deserializer.visit_string(PathBufVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -403,6 +403,16 @@ pub trait Deserializer {
|
||||
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.
|
||||
///
|
||||
/// The deserializer format is used to determine which format
|
||||
|
||||
+4
-1
@@ -10,7 +10,10 @@
|
||||
//! [github repository](https://github.com/serde-rs/serde)
|
||||
|
||||
#![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
|
||||
#![cfg_attr(feature = "nightly", feature(collections, core, 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)]
|
||||
|
||||
|
||||
@@ -566,8 +566,8 @@ impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
|
||||
{
|
||||
match self.iter.next() {
|
||||
Some((key, value)) => {
|
||||
let value = try!(serializer.visit_map_elt(key, value));
|
||||
Ok(Some(value))
|
||||
try!(serializer.visit_map_elt(key, value));
|
||||
Ok(Some(()))
|
||||
}
|
||||
None => Ok(None)
|
||||
}
|
||||
|
||||
@@ -322,6 +322,7 @@ pub trait Serializer {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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.
|
||||
#[cfg_attr(feature = "nightly", allow(len_without_is_empty))]
|
||||
pub trait MapVisitor {
|
||||
/// Serializes a map item in the serializer.
|
||||
///
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_codegen"
|
||||
version = "0.6.6"
|
||||
version = "0.6.14"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -12,15 +12,17 @@ keywords = ["serde", "serialization"]
|
||||
[features]
|
||||
default = ["with-syntex"]
|
||||
nightly = ["quasi_macros"]
|
||||
nightly-testing = ["clippy"]
|
||||
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
||||
|
||||
[build-dependencies]
|
||||
quasi_codegen = { verision = "^0.3.9", optional = true }
|
||||
syntex = { version = "^0.22.0", optional = true }
|
||||
quasi_codegen = { version = "^0.7.0", optional = true }
|
||||
syntex = { version = "^0.29.0", optional = true }
|
||||
|
||||
[dependencies]
|
||||
aster = { version = "^0.9.0", default-features = false }
|
||||
quasi = { verision = "^0.3.9", default-features = false }
|
||||
quasi_macros = { version = "^0.3.9", optional = true }
|
||||
syntex = { version = "^0.22.0", optional = true }
|
||||
syntex_syntax = { version = "^0.23.0", optional = true }
|
||||
aster = { version = "^0.13.1", default-features = false }
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
quasi = { version = "^0.7.0", default-features = false }
|
||||
quasi_macros = { version = "^0.7.0", optional = true }
|
||||
syntex = { version = "^0.29.0", optional = true }
|
||||
syntex_syntax = { version = "^0.29.0", optional = true }
|
||||
|
||||
+98
-26
@@ -4,6 +4,7 @@ use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::print::pprust::meta_item_to_string;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use aster;
|
||||
@@ -32,7 +33,7 @@ impl FieldAttrs {
|
||||
/// Return a set of formats that the field has attributes for.
|
||||
pub fn formats(&self) -> HashSet<P<ast::Expr>> {
|
||||
match self.names {
|
||||
FieldNames::Format{ref formats, default: _} => {
|
||||
FieldNames::Format { ref formats, .. } => {
|
||||
let mut set = HashSet::new();
|
||||
for (fmt, _) in formats.iter() {
|
||||
set.insert(fmt.clone());
|
||||
@@ -70,7 +71,7 @@ impl FieldAttrs {
|
||||
pub fn default_key_expr(&self) -> &P<ast::Expr> {
|
||||
match self.names {
|
||||
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> {
|
||||
cx: &'a ExtCtxt<'a>,
|
||||
builder: &'a aster::AstBuilder,
|
||||
skip_serializing_field: bool,
|
||||
skip_serializing_field_if_empty: bool,
|
||||
@@ -114,8 +116,10 @@ pub struct 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 {
|
||||
cx: cx,
|
||||
builder: builder,
|
||||
skip_serializing_field: 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 {
|
||||
ast::NamedField(name, _) => {
|
||||
self.name = Some(self.builder.expr().str(name));
|
||||
@@ -137,33 +141,41 @@ impl<'a> FieldAttrsBuilder<'a> {
|
||||
self.attrs(&field.node.attrs)
|
||||
}
|
||||
|
||||
pub fn attrs(self, attrs: &[ast::Attribute]) -> FieldAttrsBuilder<'a> {
|
||||
attrs.iter().fold(self, FieldAttrsBuilder::attr)
|
||||
pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result<FieldAttrsBuilder<'a>, ()> {
|
||||
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 {
|
||||
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
||||
ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => {
|
||||
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 {
|
||||
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()));
|
||||
|
||||
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 {
|
||||
match item.node {
|
||||
ast::MetaNameValue(ref name, ref lit) => {
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) => {
|
||||
let name = self.builder.expr().str(name);
|
||||
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" => {
|
||||
self.default()
|
||||
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
||||
Ok(self.default())
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing" => {
|
||||
self.skip_serializing_field()
|
||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => {
|
||||
Ok(self.skip_serializing_field())
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_empty" => {
|
||||
self.skip_serializing_field_if_empty()
|
||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_empty" => {
|
||||
Ok(self.skip_serializing_field_if_empty())
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_none" => {
|
||||
self.skip_serializing_field_if_none()
|
||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_none" => {
|
||||
Ok(self.skip_serializing_field_if_none())
|
||||
}
|
||||
_ => {
|
||||
// Ignore unknown meta variables for now.
|
||||
self
|
||||
self.cx.span_err(
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+151
-137
@@ -5,7 +5,6 @@ use aster;
|
||||
use syntax::ast::{
|
||||
self,
|
||||
EnumDef,
|
||||
Expr,
|
||||
Ident,
|
||||
Item,
|
||||
MetaItem,
|
||||
@@ -13,7 +12,6 @@ use syntax::ast::{
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use attr;
|
||||
@@ -31,7 +29,7 @@ pub fn expand_derive_deserialize(
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
"`derive` may only be applied to structs and enums");
|
||||
"`#[derive(Deserialize)]` may only be applied to structs and enums");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -39,9 +37,14 @@ pub fn expand_derive_deserialize(
|
||||
let builder = aster::AstBuilder::new().span(span);
|
||||
|
||||
let generics = match item.node {
|
||||
ast::ItemStruct(_, ref generics) => generics,
|
||||
ast::ItemEnum(_, ref generics) => generics,
|
||||
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Deserialize)]")
|
||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||
_ => {
|
||||
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())
|
||||
@@ -54,13 +57,13 @@ pub fn expand_derive_deserialize(
|
||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||
.build();
|
||||
|
||||
let body = deserialize_body(
|
||||
cx,
|
||||
&builder,
|
||||
&item,
|
||||
&impl_generics,
|
||||
ty.clone(),
|
||||
);
|
||||
let body = match deserialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
|
||||
Ok(body) => body,
|
||||
Err(()) => {
|
||||
// An error occured, but it should have been reported already.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
@@ -83,19 +86,24 @@ fn deserialize_body(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
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 {
|
||||
ast::ItemStruct(ref variant_data, _) => {
|
||||
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||
deserialize_item_struct(
|
||||
cx,
|
||||
builder,
|
||||
item,
|
||||
impl_generics,
|
||||
ty,
|
||||
item.span,
|
||||
variant_data,
|
||||
)
|
||||
}
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
deserialize_item_enum(
|
||||
cx,
|
||||
builder,
|
||||
@@ -105,7 +113,10 @@ fn deserialize_body(
|
||||
enum_def,
|
||||
)
|
||||
}
|
||||
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Deserialize)]")
|
||||
_ => {
|
||||
cx.span_bug(item.span,
|
||||
"expected ItemStruct or ItemEnum in #[derive(Deserialize)]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +126,9 @@ fn deserialize_item_struct(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
span: Span,
|
||||
variant_data: &ast::VariantData,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
match *variant_data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
deserialize_unit_struct(
|
||||
@@ -136,7 +148,7 @@ fn deserialize_item_struct(
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
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(
|
||||
@@ -150,7 +162,7 @@ fn deserialize_item_struct(
|
||||
}
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
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(
|
||||
@@ -172,14 +184,14 @@ fn deserialize_visitor(
|
||||
trait_generics: &ast::Generics,
|
||||
forward_ty_params: Vec<ast::TyParam>,
|
||||
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() {
|
||||
(
|
||||
Ok((
|
||||
builder.item().tuple_struct("__Visitor").build(),
|
||||
builder.ty().id("__Visitor"),
|
||||
builder.expr().id("__Visitor"),
|
||||
trait_generics.clone(),
|
||||
)
|
||||
))
|
||||
} else {
|
||||
let placeholders : Vec<_> = trait_generics.ty_params.iter()
|
||||
.map(|t| builder.ty().id(t.ident))
|
||||
@@ -187,9 +199,9 @@ fn deserialize_visitor(
|
||||
let mut trait_generics = trait_generics.clone();
|
||||
let mut ty_params = forward_ty_params.clone();
|
||||
ty_params.extend(trait_generics.ty_params.into_vec());
|
||||
trait_generics.ty_params = OwnedSlice::from_vec(ty_params);
|
||||
trait_generics.ty_params = P::from_vec(ty_params);
|
||||
|
||||
(
|
||||
Ok((
|
||||
builder.item().tuple_struct("__Visitor")
|
||||
.generics().with(trait_generics.clone()).build()
|
||||
.with_tys({
|
||||
@@ -227,7 +239,7 @@ fn deserialize_visitor(
|
||||
})
|
||||
.build(),
|
||||
trait_generics,
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +263,10 @@ fn deserialize_unit_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
struct __Visitor;
|
||||
|
||||
impl ::serde::de::Visitor for __Visitor {
|
||||
@@ -277,7 +289,7 @@ fn deserialize_unit_struct(
|
||||
}
|
||||
|
||||
deserializer.visit_unit_struct($type_name, __Visitor)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(
|
||||
@@ -286,16 +298,15 @@ fn deserialize_newtype_struct(
|
||||
type_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
||||
deserialize_visitor(
|
||||
builder,
|
||||
impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
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)],
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
@@ -306,7 +317,7 @@ fn deserialize_newtype_struct(
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
|
||||
@@ -329,7 +340,7 @@ fn deserialize_newtype_struct(
|
||||
}
|
||||
|
||||
deserializer.visit_newtype_struct($type_name, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct(
|
||||
@@ -339,16 +350,15 @@ fn deserialize_tuple_struct(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
||||
deserialize_visitor(
|
||||
builder,
|
||||
impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
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)],
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
@@ -359,7 +369,7 @@ fn deserialize_tuple_struct(
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
|
||||
@@ -374,7 +384,7 @@ fn deserialize_tuple_struct(
|
||||
}
|
||||
|
||||
deserializer.visit_tuple_struct($type_name, $fields, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_seq(
|
||||
@@ -383,7 +393,7 @@ fn deserialize_seq(
|
||||
struct_path: ast::Path,
|
||||
fields: usize,
|
||||
) -> P<ast::Expr> {
|
||||
let let_values: Vec<P<ast::Stmt>> = (0 .. fields)
|
||||
let let_values: Vec<ast::Stmt> = (0 .. fields)
|
||||
.map(|i| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
quote_stmt!(cx,
|
||||
@@ -416,8 +426,8 @@ fn deserialize_struct_as_seq(
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let let_values: Vec<P<ast::Stmt>> = (0 .. fields.len())
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let let_values: Vec<ast::Stmt> = (0 .. fields.len())
|
||||
.map(|i| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
quote_stmt!(cx,
|
||||
@@ -439,7 +449,9 @@ fn deserialize_struct_as_seq(
|
||||
(
|
||||
match field.node.kind {
|
||||
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)),
|
||||
)
|
||||
@@ -447,13 +459,13 @@ fn deserialize_struct_as_seq(
|
||||
)
|
||||
.build();
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$let_values
|
||||
|
||||
try!(visitor.end());
|
||||
|
||||
Ok($result)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_struct(
|
||||
@@ -463,35 +475,35 @@ fn deserialize_struct(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
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,
|
||||
&impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
));
|
||||
|
||||
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,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
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,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
fields,
|
||||
);
|
||||
));
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$field_visitor
|
||||
|
||||
$visitor_item
|
||||
@@ -517,7 +529,7 @@ fn deserialize_struct(
|
||||
$fields_stmt
|
||||
|
||||
deserializer.visit_struct($type_name, FIELDS, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_item_enum(
|
||||
@@ -527,7 +539,7 @@ fn deserialize_item_enum(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
enum_def: &EnumDef,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
@@ -538,7 +550,7 @@ fn deserialize_item_enum(
|
||||
enum_def.variants.iter()
|
||||
.map(|variant| {
|
||||
let expr = builder.expr().str(variant.node.name);
|
||||
attr::FieldAttrsBuilder::new(builder)
|
||||
attr::FieldAttrsBuilder::new(cx, builder)
|
||||
.name(expr)
|
||||
.default()
|
||||
.build()
|
||||
@@ -546,7 +558,7 @@ fn deserialize_item_enum(
|
||||
.collect()
|
||||
);
|
||||
|
||||
let variants_expr = builder.expr().addr_of().slice()
|
||||
let variants_expr = builder.expr().ref_().slice()
|
||||
.with_exprs(
|
||||
enum_def.variants.iter()
|
||||
.map(|variant| {
|
||||
@@ -560,35 +572,33 @@ fn deserialize_item_enum(
|
||||
).unwrap();
|
||||
|
||||
// Match arms to extract a variant from a string
|
||||
let variant_arms: Vec<_> = enum_def.variants.iter()
|
||||
.enumerate()
|
||||
.map(|(i, variant)| {
|
||||
let variant_name = builder.pat().enum_()
|
||||
.id("__Field").id(format!("__field{}", i)).build()
|
||||
.build();
|
||||
let mut variant_arms = vec![];
|
||||
for (i, variant) in enum_def.variants.iter().enumerate() {
|
||||
let variant_name = builder.pat().path()
|
||||
.id("__Field").id(format!("__field{}", i))
|
||||
.build();
|
||||
|
||||
let expr = deserialize_variant(
|
||||
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(
|
||||
let expr = try!(deserialize_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
ty.clone(),
|
||||
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
|
||||
|
||||
$visitor_item
|
||||
@@ -608,7 +618,7 @@ fn deserialize_item_enum(
|
||||
$variants_stmt
|
||||
|
||||
deserializer.visit_enum($type_name, VARIANTS, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_variant(
|
||||
@@ -618,21 +628,21 @@ fn deserialize_variant(
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
variant: &ast::Variant,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let variant_ident = variant.node.name;
|
||||
|
||||
match variant.node.data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
try!(visitor.visit_unit());
|
||||
Ok($type_ident::$variant_ident)
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::VariantData::Tuple(ref args, _) if args.len() == 1 => {
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
let val = try!(visitor.visit_newtype());
|
||||
Ok($type_ident::$variant_ident(val))
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
deserialize_tuple_variant(
|
||||
@@ -667,16 +677,15 @@ fn deserialize_tuple_variant(
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
||||
deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
@@ -685,7 +694,7 @@ fn deserialize_tuple_variant(
|
||||
fields,
|
||||
);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
|
||||
@@ -699,7 +708,7 @@ fn deserialize_tuple_variant(
|
||||
}
|
||||
|
||||
visitor.visit_tuple($fields, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_struct_variant(
|
||||
@@ -710,7 +719,7 @@ fn deserialize_struct_variant(
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let type_path = builder.path()
|
||||
@@ -718,29 +727,28 @@ fn deserialize_struct_variant(
|
||||
.id(variant_ident)
|
||||
.build();
|
||||
|
||||
let visit_seq_expr = deserialize_struct_as_seq(
|
||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||
cx,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
fields,
|
||||
);
|
||||
));
|
||||
|
||||
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor(
|
||||
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
type_path,
|
||||
fields,
|
||||
);
|
||||
));
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
||||
deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$field_visitor
|
||||
|
||||
$visitor_item
|
||||
@@ -766,7 +774,7 @@ fn deserialize_struct_variant(
|
||||
$fields_stmt
|
||||
|
||||
visitor.visit_struct(FIELDS, $visitor_expr)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_field_visitor(
|
||||
@@ -909,7 +917,7 @@ fn deserialize_field_visitor(
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.visit(__FieldVisitor::<D>{ phantom: PhantomData })
|
||||
deserializer.visit_struct_field(__FieldVisitor::<D>{ phantom: PhantomData })
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
@@ -922,27 +930,29 @@ fn deserialize_struct_visitor(
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
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(
|
||||
cx,
|
||||
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,
|
||||
builder,
|
||||
struct_path,
|
||||
fields,
|
||||
);
|
||||
));
|
||||
|
||||
let fields_expr = builder.expr().addr_of().slice()
|
||||
let fields_expr = builder.expr().ref_().slice()
|
||||
.with_exprs(
|
||||
fields.iter()
|
||||
.map(|field| {
|
||||
match field.node.kind {
|
||||
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")
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -952,7 +962,7 @@ fn deserialize_struct_visitor(
|
||||
const FIELDS: &'static [&'static str] = $fields_expr;
|
||||
).unwrap();
|
||||
|
||||
(field_visitor, fields_stmt, visit_map_expr)
|
||||
Ok((field_visitor, fields_stmt, visit_map_expr))
|
||||
}
|
||||
|
||||
fn deserialize_map(
|
||||
@@ -960,14 +970,14 @@ fn deserialize_map(
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
// Create the field names for the fields.
|
||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||
.map(|i| builder.id(format!("__field{}", i)))
|
||||
.collect();
|
||||
|
||||
// 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())
|
||||
.collect();
|
||||
|
||||
@@ -982,8 +992,10 @@ fn deserialize_map(
|
||||
})
|
||||
.collect();
|
||||
|
||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
||||
.zip(field::struct_field_attrs(cx, builder, fields).iter())
|
||||
let field_attrs = try!(field::struct_field_attrs(cx, builder, fields));
|
||||
|
||||
let extract_values: Vec<ast::Stmt> = field_names.iter()
|
||||
.zip(field_attrs.iter())
|
||||
.map(|(field_name, field_attr)| {
|
||||
let missing_expr = if field_attr.use_default() {
|
||||
quote_expr!(cx, ::std::default::Default::default())
|
||||
@@ -1026,7 +1038,9 @@ fn deserialize_map(
|
||||
(
|
||||
match field.node.kind {
|
||||
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),
|
||||
)
|
||||
@@ -1034,7 +1048,7 @@ fn deserialize_map(
|
||||
)
|
||||
.build();
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$let_values
|
||||
|
||||
while let Some(key) = try!(visitor.visit_key()) {
|
||||
@@ -1048,5 +1062,5 @@ fn deserialize_map(
|
||||
try!(visitor.end());
|
||||
|
||||
Ok($result)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -2,16 +2,29 @@ use syntax::ast;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
|
||||
use aster;
|
||||
use attr::{FieldAttrs, FieldAttrsBuilder};
|
||||
use attr;
|
||||
|
||||
pub fn struct_field_attrs(
|
||||
_cx: &ExtCtxt,
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
fields: &[ast::StructField],
|
||||
) -> Vec<FieldAttrs> {
|
||||
fields.iter()
|
||||
.map(|field| {
|
||||
FieldAttrsBuilder::new(builder).field(field).build()
|
||||
})
|
||||
.collect()
|
||||
) -> Result<Vec<attr::FieldAttrs>, ()> {
|
||||
let mut attrs = vec![];
|
||||
for field in fields {
|
||||
let builder = attr::FieldAttrsBuilder::new(cx, builder);
|
||||
let builder = try!(builder.field(field));
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -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"), plugin(quasi_macros))]
|
||||
|
||||
@@ -16,6 +19,9 @@ extern crate syntax;
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
extern crate rustc_plugin;
|
||||
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
use syntax::feature_gate::AttributeType;
|
||||
|
||||
#[cfg(feature = "with-syntex")]
|
||||
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
||||
|
||||
@@ -26,14 +32,6 @@ include!("lib.rs.in");
|
||||
pub fn register(reg: &mut syntex::Registry) {
|
||||
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.
|
||||
#[cfg(feature = "with-syntex")]
|
||||
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
|
||||
@@ -43,7 +41,7 @@ pub fn register(reg: &mut syntex::Registry) {
|
||||
impl fold::Folder for StripAttributeFolder {
|
||||
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
||||
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)
|
||||
}
|
||||
|
||||
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"))]
|
||||
@@ -70,4 +76,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
|
||||
syntax::parse::token::intern("derive_Deserialize"),
|
||||
syntax::ext::base::MultiDecorator(
|
||||
Box::new(de::expand_derive_deserialize)));
|
||||
|
||||
reg.register_attribute("serde".to_owned(), AttributeType::Normal);
|
||||
}
|
||||
|
||||
+99
-74
@@ -4,7 +4,6 @@ use syntax::ast::{
|
||||
Ident,
|
||||
MetaItem,
|
||||
Item,
|
||||
Expr,
|
||||
};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
@@ -12,7 +11,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use field::struct_field_attrs;
|
||||
use field;
|
||||
|
||||
pub fn expand_derive_serialize(
|
||||
cx: &mut ExtCtxt,
|
||||
@@ -26,7 +25,7 @@ pub fn expand_derive_serialize(
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
"`derive` may only be applied to structs and enums");
|
||||
"`#[derive(Serialize)]` may only be applied to structs and enums");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -34,9 +33,14 @@ pub fn expand_derive_serialize(
|
||||
let builder = aster::AstBuilder::new().span(span);
|
||||
|
||||
let generics = match item.node {
|
||||
ast::ItemStruct(_, ref generics) => generics,
|
||||
ast::ItemEnum(_, ref generics) => generics,
|
||||
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Serialize)]")
|
||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||
_ => {
|
||||
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())
|
||||
@@ -49,13 +53,13 @@ pub fn expand_derive_serialize(
|
||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||
.build();
|
||||
|
||||
let body = serialize_body(
|
||||
cx,
|
||||
&builder,
|
||||
&item,
|
||||
&impl_generics,
|
||||
ty.clone(),
|
||||
);
|
||||
let body = match serialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
|
||||
Ok(body) => body,
|
||||
Err(()) => {
|
||||
// An error occured, but it should have been reported already.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
@@ -78,19 +82,24 @@ fn serialize_body(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
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 {
|
||||
ast::ItemStruct(ref variant_data, _) => {
|
||||
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||
serialize_item_struct(
|
||||
cx,
|
||||
builder,
|
||||
item,
|
||||
impl_generics,
|
||||
ty,
|
||||
item.span,
|
||||
variant_data,
|
||||
)
|
||||
}
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
serialize_item_enum(
|
||||
cx,
|
||||
builder,
|
||||
@@ -100,7 +109,10 @@ fn serialize_body(
|
||||
enum_def,
|
||||
)
|
||||
}
|
||||
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive(Serialize)]")
|
||||
_ => {
|
||||
cx.span_bug(item.span,
|
||||
"expected ItemStruct or ItemEnum in #[derive(Serialize)]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +122,9 @@ fn serialize_item_struct(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
span: Span,
|
||||
variant_data: &ast::VariantData,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
match *variant_data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
serialize_unit_struct(
|
||||
@@ -129,7 +142,7 @@ fn serialize_item_struct(
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
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(
|
||||
@@ -143,7 +156,7 @@ fn serialize_item_struct(
|
||||
}
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
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(
|
||||
@@ -162,20 +175,24 @@ fn serialize_unit_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
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(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
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(
|
||||
@@ -185,7 +202,7 @@ fn serialize_tuple_struct(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
@@ -200,7 +217,7 @@ fn serialize_tuple_struct(
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_struct
|
||||
$visitor_impl
|
||||
serializer.visit_tuple_struct($type_name, Visitor {
|
||||
@@ -208,7 +225,7 @@ fn serialize_tuple_struct(
|
||||
state: 0,
|
||||
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
@@ -218,8 +235,13 @@ fn serialize_struct(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
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,
|
||||
builder,
|
||||
ty.clone(),
|
||||
@@ -229,15 +251,12 @@ fn serialize_struct(
|
||||
.build_ty(ty.clone()),
|
||||
fields,
|
||||
impl_generics,
|
||||
fields.iter().map(|field| {
|
||||
let name = field.node.ident().expect("struct has unnamed field");
|
||||
quote_expr!(cx, &self.value.$name)
|
||||
})
|
||||
);
|
||||
value_exprs,
|
||||
));
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_struct
|
||||
$visitor_impl
|
||||
serializer.visit_struct($type_name, Visitor {
|
||||
@@ -245,7 +264,7 @@ fn serialize_struct(
|
||||
state: 0,
|
||||
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn serialize_item_enum(
|
||||
@@ -255,27 +274,28 @@ fn serialize_item_enum(
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
enum_def: &ast::EnumDef,
|
||||
) -> P<ast::Expr> {
|
||||
let arms: Vec<ast::Arm> = enum_def.variants.iter()
|
||||
.enumerate()
|
||||
.map(|(variant_index, variant)| {
|
||||
serialize_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
impl_generics,
|
||||
ty.clone(),
|
||||
variant,
|
||||
variant_index,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let mut arms = vec![];
|
||||
|
||||
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 {
|
||||
$arms
|
||||
}
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_variant(
|
||||
@@ -286,18 +306,18 @@ fn serialize_variant(
|
||||
ty: P<ast::Ty>,
|
||||
variant: &ast::Variant,
|
||||
variant_index: usize,
|
||||
) -> ast::Arm {
|
||||
) -> Result<ast::Arm, ()> {
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
let variant_ident = variant.node.name;
|
||||
let variant_name = builder.expr().str(variant_ident);
|
||||
|
||||
match variant.node.data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
let pat = builder.pat().enum_()
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
let pat = builder.pat().path()
|
||||
.id(type_ident).id(variant_ident)
|
||||
.build();
|
||||
|
||||
quote_arm!(cx,
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => {
|
||||
::serde::ser::Serializer::visit_unit_variant(
|
||||
serializer,
|
||||
@@ -306,7 +326,7 @@ fn serialize_variant(
|
||||
$variant_name,
|
||||
)
|
||||
}
|
||||
)
|
||||
))
|
||||
},
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
let field = builder.id("__simple_value");
|
||||
@@ -315,7 +335,8 @@ fn serialize_variant(
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
.with_pats(Some(field).into_iter())
|
||||
.build();
|
||||
quote_arm!(cx,
|
||||
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => {
|
||||
::serde::ser::Serializer::visit_newtype_variant(
|
||||
serializer,
|
||||
@@ -325,7 +346,7 @@ fn serialize_variant(
|
||||
__simple_value,
|
||||
)
|
||||
}
|
||||
)
|
||||
))
|
||||
},
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||
@@ -352,7 +373,9 @@ fn serialize_variant(
|
||||
field_names,
|
||||
);
|
||||
|
||||
quote_arm!(cx, $pat => { $expr })
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => { $expr }
|
||||
))
|
||||
}
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
let field_names: Vec<_> = (0 .. fields.len())
|
||||
@@ -368,7 +391,7 @@ fn serialize_variant(
|
||||
let name = match field.node.kind {
|
||||
ast::NamedField(name, _) => name,
|
||||
ast::UnnamedField(_) => {
|
||||
cx.bug("struct variant has unnamed fields")
|
||||
cx.span_bug(field.span, "struct variant has unnamed fields")
|
||||
}
|
||||
};
|
||||
|
||||
@@ -377,7 +400,7 @@ fn serialize_variant(
|
||||
)
|
||||
.build();
|
||||
|
||||
let expr = serialize_struct_variant(
|
||||
let expr = try!(serialize_struct_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_name,
|
||||
@@ -387,9 +410,11 @@ fn serialize_variant(
|
||||
ty,
|
||||
fields,
|
||||
field_names,
|
||||
);
|
||||
));
|
||||
|
||||
quote_arm!(cx, $pat => { $expr })
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => { $expr }
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +479,7 @@ fn serialize_struct_variant(
|
||||
structure_ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
field_names: Vec<Ident>,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, ()> {
|
||||
let value_ty = builder.ty().tuple()
|
||||
.with_tys(
|
||||
fields.iter().map(|field| {
|
||||
@@ -474,7 +499,7 @@ fn serialize_struct_variant(
|
||||
)
|
||||
.build();
|
||||
|
||||
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
@@ -486,9 +511,9 @@ fn serialize_struct_variant(
|
||||
.tup_field(i)
|
||||
.field("value").self_()
|
||||
})
|
||||
);
|
||||
));
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_struct
|
||||
$visitor_impl
|
||||
serializer.visit_struct_variant($type_name, $variant_index, $variant_name, Visitor {
|
||||
@@ -496,7 +521,7 @@ fn serialize_struct_variant(
|
||||
state: 0,
|
||||
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct_visitor(
|
||||
@@ -574,12 +599,12 @@ fn serialize_struct_visitor<I>(
|
||||
fields: &[ast::StructField],
|
||||
generics: &ast::Generics,
|
||||
value_exprs: I,
|
||||
) -> (P<ast::Item>, P<ast::Item>)
|
||||
) -> Result<(P<ast::Item>, P<ast::Item>), ()>
|
||||
where I: Iterator<Item=P<ast::Expr>>,
|
||||
{
|
||||
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()
|
||||
.zip(value_exprs.iter())
|
||||
@@ -642,7 +667,7 @@ fn serialize_struct_visitor<I>(
|
||||
})
|
||||
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
|
||||
|
||||
(
|
||||
Ok((
|
||||
quote_item!(cx,
|
||||
struct Visitor $visitor_impl_generics $where_clause {
|
||||
state: usize,
|
||||
@@ -674,5 +699,5 @@ fn serialize_struct_visitor<I>(
|
||||
}
|
||||
}
|
||||
).unwrap(),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
+16
-3
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_macros"
|
||||
version = "0.6.6"
|
||||
version = "0.6.14"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -12,10 +12,23 @@ keywords = ["serde", "serialization"]
|
||||
name = "serde_macros"
|
||||
plugin = true
|
||||
|
||||
[features]
|
||||
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
|
||||
|
||||
[dependencies]
|
||||
serde_codegen = { version = "*", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
serde_codegen = { version = "^0.6.14", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
|
||||
[dev-dependencies]
|
||||
compiletest_rs = "^0.0.11"
|
||||
num = "^0.1.27"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "*", path = "../serde", features = ["nightly", "num-impls"] }
|
||||
serde = { version = "^0.6.14", path = "../serde", features = ["num-impls"] }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
path = "tests/test.rs"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
path = "benches/bench.rs"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![feature(custom_attribute, custom_derive, plugin, test)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
||||
#![plugin(serde_macros)]
|
||||
|
||||
extern crate num;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
#![cfg_attr(feature = "clippy", feature(plugin))]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
||||
|
||||
extern crate serde_codegen;
|
||||
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() { }
|
||||
@@ -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");
|
||||
}
|
||||
@@ -6,3 +6,5 @@ extern crate serde;
|
||||
extern crate test;
|
||||
|
||||
include!("../../serde_tests/tests/test.rs.in");
|
||||
|
||||
mod compile_tests;
|
||||
|
||||
+12
-6
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_tests"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -10,16 +10,22 @@ readme = "README.md"
|
||||
keywords = ["serialization"]
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
|
||||
|
||||
[build-dependencies]
|
||||
syntex = { version = "^0.22.0" }
|
||||
syntex_syntax = { version = "^0.23.0" }
|
||||
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
|
||||
syntex = { version = "^0.29.0" }
|
||||
syntex_syntax = { version = "^0.29.0" }
|
||||
serde_codegen = { version = "^0.6.14", path = "../serde_codegen", features = ["with-syntex"] }
|
||||
|
||||
[dev-dependencies]
|
||||
num = "^0.1.27"
|
||||
num = "^0.1.26"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "*", path = "../serde", features = ["num-impls"] }
|
||||
syntex = "^0.22.0"
|
||||
syntex = "^0.29.0"
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#![feature(test)]
|
||||
#![cfg_attr(feature = "nightly", feature(plugin))]
|
||||
#![cfg_attr(feature = "nightly", plugin(clippy))]
|
||||
|
||||
extern crate num;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
@@ -415,7 +415,7 @@ fn bench_decoder_dog(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn bench_decoder_frog(b: &mut Bencher) {
|
||||
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 value: Animal = Decodable::decode(&mut d).unwrap();
|
||||
@@ -439,7 +439,7 @@ fn bench_deserializer_dog(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn bench_deserializer_frog(b: &mut Bencher) {
|
||||
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 value: Animal = Deserialize::deserialize(&mut d).unwrap();
|
||||
|
||||
@@ -399,7 +399,7 @@ fn bench_decoder_000(b: &mut Bencher) {
|
||||
fn bench_decoder_003(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut m: HashMap<String, isize> = HashMap::new();
|
||||
for i in (0 .. 3) {
|
||||
for i in 0 .. 3 {
|
||||
m.insert(i.to_string(), i);
|
||||
}
|
||||
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) {
|
||||
b.iter(|| {
|
||||
let mut m: HashMap<String, isize> = HashMap::new();
|
||||
for i in (0 .. 100) {
|
||||
for i in 0 .. 100 {
|
||||
m.insert(i.to_string(), i);
|
||||
}
|
||||
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) {
|
||||
b.iter(|| {
|
||||
let mut m: HashMap<String, isize> = HashMap::new();
|
||||
for i in (0 .. 3) {
|
||||
for i in 0 .. 3 {
|
||||
m.insert(i.to_string(), i);
|
||||
}
|
||||
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) {
|
||||
b.iter(|| {
|
||||
let mut m: HashMap<String, isize> = HashMap::new();
|
||||
for i in (0 .. 100) {
|
||||
for i in 0 .. 100 {
|
||||
m.insert(i.to_string(), i);
|
||||
}
|
||||
run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m)
|
||||
|
||||
@@ -614,7 +614,7 @@ mod deserializer {
|
||||
fn bench_decoder_0_0(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("abc".to_string(), Some('c'));
|
||||
map.insert("abc".to_owned(), Some('c'));
|
||||
|
||||
let outer = Outer {
|
||||
inner: vec!(),
|
||||
@@ -653,11 +653,11 @@ fn bench_decoder_1_0(b: &mut Bencher) {
|
||||
fn bench_decoder_1_5(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("1".to_string(), Some('a'));
|
||||
map.insert("2".to_string(), None);
|
||||
map.insert("3".to_string(), Some('b'));
|
||||
map.insert("4".to_string(), None);
|
||||
map.insert("5".to_string(), Some('c'));
|
||||
map.insert("1".to_owned(), Some('a'));
|
||||
map.insert("2".to_owned(), None);
|
||||
map.insert("3".to_owned(), Some('b'));
|
||||
map.insert("4".to_owned(), None);
|
||||
map.insert("5".to_owned(), Some('c'));
|
||||
|
||||
let outer = Outer {
|
||||
inner: vec!(
|
||||
@@ -716,11 +716,11 @@ fn bench_deserializer_1_0(b: &mut Bencher) {
|
||||
fn bench_deserializer_1_5(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("1".to_string(), Some('a'));
|
||||
map.insert("2".to_string(), None);
|
||||
map.insert("3".to_string(), Some('b'));
|
||||
map.insert("4".to_string(), None);
|
||||
map.insert("5".to_string(), Some('c'));
|
||||
map.insert("1".to_owned(), Some('a'));
|
||||
map.insert("2".to_owned(), None);
|
||||
map.insert("3".to_owned(), Some('b'));
|
||||
map.insert("4".to_owned(), None);
|
||||
map.insert("5".to_owned(), Some('c'));
|
||||
|
||||
let outer = Outer {
|
||||
inner: vec!(
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#![cfg_attr(feature = "nightly", feature(plugin))]
|
||||
#![cfg_attr(feature = "nightly", plugin(clippy))]
|
||||
|
||||
extern crate num;
|
||||
extern crate serde;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use num::FromPrimitive;
|
||||
use num::bigint::{BigInt, BigUint};
|
||||
@@ -95,12 +96,12 @@ declare_tests! {
|
||||
test_char {
|
||||
'a' => vec![Token::Char('a')],
|
||||
'a' => vec![Token::Str("a")],
|
||||
'a' => vec![Token::String("a".to_string())],
|
||||
'a' => vec![Token::String("a".to_owned())],
|
||||
}
|
||||
test_string {
|
||||
"abc".to_string() => vec![Token::Str("abc")],
|
||||
"abc".to_string() => vec![Token::String("abc".to_string())],
|
||||
"a".to_string() => vec![Token::Char('a')],
|
||||
"abc".to_owned() => vec![Token::Str("abc")],
|
||||
"abc".to_owned() => vec![Token::String("abc".to_owned())],
|
||||
"a".to_owned() => vec![Token::Char('a')],
|
||||
}
|
||||
test_option {
|
||||
None::<i32> => vec![Token::Unit],
|
||||
@@ -589,4 +590,9 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_path_buf {
|
||||
PathBuf::from("/usr/local/lib") => vec![
|
||||
Token::String("/usr/local/lib".to_owned()),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use num::FromPrimitive;
|
||||
use num::bigint::{BigInt, BigUint};
|
||||
@@ -63,7 +64,7 @@ declare_ser_tests! {
|
||||
}
|
||||
test_str {
|
||||
"abc" => &[Token::Str("abc")],
|
||||
"abc".to_string() => &[Token::Str("abc")],
|
||||
"abc".to_owned() => &[Token::Str("abc")],
|
||||
}
|
||||
test_option {
|
||||
None::<i32> => &[Token::Option(false)],
|
||||
@@ -293,4 +294,14 @@ declare_ser_tests! {
|
||||
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"),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ impl de::Error for Error {
|
||||
fn end_of_stream() -> Error { Error::EndOfStreamError }
|
||||
|
||||
fn unknown_field(field: &str) -> Error {
|
||||
Error::UnknownFieldError(field.to_string())
|
||||
Error::UnknownFieldError(field.to_owned())
|
||||
}
|
||||
|
||||
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>
|
||||
where V: de::Visitor,
|
||||
{
|
||||
println!("visit {:?}", self.tokens.peek());
|
||||
match self.tokens.next() {
|
||||
Some(Token::Bool(v)) => visitor.visit_bool(v),
|
||||
Some(Token::Isize(v)) => visitor.visit_isize(v),
|
||||
|
||||
Reference in New Issue
Block a user