mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-05-06 00:57:56 +00:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41142d41ee | |||
| fd328c2f2a | |||
| 3ad276944a | |||
| bb20796e9d | |||
| 709ac64dfc | |||
| a9a4b2d8e2 | |||
| 7374ac499d | |||
| 6596f77e91 | |||
| eeb4efc19c | |||
| 76b70455ec | |||
| f43c8a6267 | |||
| 7aa0b6ce27 | |||
| efdbf5795f | |||
| 55355b6680 | |||
| f8a91e5176 | |||
| aa0cd9b3dc | |||
| 1f82cd6e3d | |||
| 3caac4e6f3 | |||
| f4414bfc14 | |||
| 8378267b9b | |||
| 9c0140968d | |||
| 5716e8c508 | |||
| 0e9d45da60 | |||
| 6e7a75c859 | |||
| 0ff91e4451 | |||
| 305fab7c16 | |||
| a959073a81 | |||
| 2f0fc6e6f1 | |||
| 7bd87feb62 | |||
| bff2301ac3 | |||
| fd3c15fb68 | |||
| 808b06940e | |||
| 8cce6ecf15 | |||
| ef97f87b96 | |||
| 93a7568ff6 | |||
| 0439bb9d02 | |||
| 886670134a | |||
| 65e36647f5 | |||
| 51fdb0e4ef | |||
| a4de662adb | |||
| ff02b0c741 | |||
| 6b3958d5fc | |||
| 84b289dd7b | |||
| dbba537b66 | |||
| bc2324fba7 | |||
| 9082b75e75 | |||
| 4b9f751d74 | |||
| 451700d3d2 | |||
| 1c5d83889c | |||
| f659fa8919 | |||
| 87393b61bb | |||
| a84b6aaedd | |||
| ac98a25291 | |||
| 48dd47b2b7 | |||
| 4af850431c | |||
| 95c5e8681e | |||
| c7c5b50f35 | |||
| a8509a1d03 | |||
| d9b6feef19 | |||
| b526404707 | |||
| 9785646246 | |||
| 332b51f58a | |||
| fb18a5cc56 | |||
| b1cab411d6 | |||
| b01fc032fd | |||
| f771eea6e6 | |||
| 6b127cb8d0 | |||
| d0a63b451c | |||
| 8296ff4bad | |||
| eaff73a541 | |||
| 19ec8bbdb9 | |||
| 4d4b85318f |
+21
-28
@@ -1,43 +1,36 @@
|
|||||||
language: rust
|
language: rust
|
||||||
sudo: false
|
|
||||||
|
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
|
- 1.5.0
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- libcurl4-openssl-dev
|
- libcurl4-openssl-dev
|
||||||
- libelf-dev
|
- libelf-dev
|
||||||
- libdw-dev
|
- libdw-dev
|
||||||
|
- binutils-dev
|
||||||
before_script:
|
before_script:
|
||||||
- |
|
- pip install 'travis-cargo<0.2' --user
|
||||||
pip install 'travis-cargo<0.2' --user &&
|
- export PATH=$HOME/.local/bin:$PATH
|
||||||
export PATH=$HOME/.local/bin:$PATH
|
|
||||||
|
|
||||||
script:
|
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 && travis-cargo --only nightly test -- --features nightly-testing) &&
|
- (cd serde_tests && travis-cargo test)
|
||||||
(cd serde_tests && travis-cargo test) &&
|
- (cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing)
|
||||||
(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 test -- --features nightly-testing) &&
|
- (cd serde_macros && travis-cargo --only nightly bench -- --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)
|
- (cd serde_macros && travis-cargo --only nightly doc)
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- (cd serde && travis-cargo --only stable doc-upload)
|
- (cd serde && travis-cargo --only stable doc-upload)
|
||||||
|
#- (cd serde_codegen && travis-cargo --only stable doc-upload)
|
||||||
|
#- (cd serde_macros && travis-cargo --only nightly doc-upload)
|
||||||
- (cd serde_tests && travis-cargo coveralls --no-sudo)
|
- (cd serde_tests && travis-cargo coveralls --no-sudo)
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
# override the default `--features unstable` used for the nightly branch (optional)
|
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
|
||||||
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
|
- secure: Jcd11Jy0xLyacBUB+oKOaxKBm9iZNInenRDtNBY8GKOtqF5fHUfEjgDf538hwRl5L0FP7DLr8oK0IHmzA7lPjJxlzoKVKV3IM7bRZEYzW5DMonf/lcliuGte7SH0NVFhifM87T8HI2hjGdAb+7+m34siBR7M3AY/XjLInrvUFvY=
|
||||||
|
|
||||||
# encrypted github token for doc upload (see `GH_TOKEN` link above)
|
|
||||||
- secure: HO41LMpMXkF2In9+1sxWVu7fgolL+y9+4Q5PI6wZX2L5pDwpPJCjxaQarQXCEnoIxED1PlP03JuF7ULNz0zw1ylYhAOfOSdkxFZRnE2wMZqq6qvXBHwyMiDrAociIzoPKSGv7JVrKPsjsnd+96K6xxueIodQZrmAdyq7N/M82Mc=
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Serde Rust Serialization Framework
|
|||||||
[](https://travis-ci.org/serde-rs/serde)
|
[](https://travis-ci.org/serde-rs/serde)
|
||||||
[](https://coveralls.io/github/serde-rs/serde?branch=master)
|
[](https://coveralls.io/github/serde-rs/serde?branch=master)
|
||||||
[](https://crates.io/crates/serde)
|
[](https://crates.io/crates/serde)
|
||||||
|
[](http://clippy.bashy.io/github/serde-rs/serde/master/log)
|
||||||
|
|
||||||
Serde is a powerful framework that enables serialization libraries to
|
Serde is a powerful framework that enables serialization libraries to
|
||||||
generically serialize Rust data structures without the overhead of runtime type
|
generically serialize Rust data structures without the overhead of runtime type
|
||||||
@@ -13,8 +14,7 @@ the same speed as a hand written serializer for a specific type.
|
|||||||
|
|
||||||
Documentation is available at:
|
Documentation is available at:
|
||||||
|
|
||||||
* [serde](https://serde-rs.github.io/serde/serde/serde/serde/index.html)
|
* [serde](https://serde-rs.github.io/serde/serde/index.html)
|
||||||
* [serde\_codegen](https://serde-rs.github.io/serde/serde/serde_codegen/serde_codegen/index.html)
|
|
||||||
|
|
||||||
Using Serde with Nightly Rust and serde\_macros
|
Using Serde with Nightly Rust and serde\_macros
|
||||||
===============================================
|
===============================================
|
||||||
@@ -46,7 +46,6 @@ serde_macros = "*"
|
|||||||
#![feature(custom_derive, plugin)]
|
#![feature(custom_derive, plugin)]
|
||||||
#![plugin(serde_macros)]
|
#![plugin(serde_macros)]
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@@ -689,34 +688,41 @@ how types are serialized. Here are the supported annotations:
|
|||||||
|
|
||||||
Container Annotations:
|
Container Annotations:
|
||||||
|
|
||||||
| Annotation | Function |
|
| Annotation | Function |
|
||||||
| ---------- | -------- |
|
| ---------- | -------- |
|
||||||
| `#[serde(rename="name")` | Serialize and deserialize this container with the given name |
|
| `#[serde(rename="name")]` | Serialize and deserialize this container with the given name |
|
||||||
| `#[serde(rename(serialize="name1"))` | Serialize this container with the given name |
|
| `#[serde(rename(serialize="name1"))]` | Serialize this container with the given name |
|
||||||
| `#[serde(rename(deserialize="name1"))` | Deserialize this container with the given name |
|
| `#[serde(rename(deserialize="name1"))]` | Deserialize this container with the given name |
|
||||||
| `#[serde(deny_unknown_fields)` | Always error during serialization when encountering unknown fields. When absent, unknown fields are ignored for self-describing formats like JSON. |
|
| `#[serde(deny_unknown_fields)]` | Always error during serialization when encountering unknown fields. When absent, unknown fields are ignored for self-describing formats like JSON. |
|
||||||
|
|
||||||
Variant Annotations:
|
Variant Annotations:
|
||||||
|
|
||||||
| Annotation | Function |
|
| Annotation | Function |
|
||||||
| ---------- | -------- |
|
| ---------- | -------- |
|
||||||
| `#[serde(rename="name")` | Serialize and deserialize this variant with the given name |
|
| `#[serde(rename="name")]` | Serialize and deserialize this variant with the given name |
|
||||||
| `#[serde(rename(serialize="name1"))` | Serialize this variant with the given name |
|
| `#[serde(rename(serialize="name1"))]` | Serialize this variant with the given name |
|
||||||
| `#[serde(rename(deserialize="name1"))` | Deserialize this variant with the given name |
|
| `#[serde(rename(deserialize="name1"))]` | Deserialize this variant with the given name |
|
||||||
|
|
||||||
Field Annotations:
|
Field Annotations:
|
||||||
|
|
||||||
| Annotation | Function |
|
| Annotation | Function |
|
||||||
| ---------- | -------- |
|
| ---------- | -------- |
|
||||||
| `#[serde(rename="name")` | Serialize and deserialize this field with the given name |
|
| `#[serde(rename="name")]` | Serialize and deserialize this field with the given name |
|
||||||
| `#[serde(rename(serialize="name1"))` | Serialize this field with the given name |
|
| `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name |
|
||||||
| `#[serde(rename(deserialize="name1"))` | Deserialize this field with the given name |
|
| `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name |
|
||||||
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
| `#[serde(default)]` | If the value is not specified, use the `Default::default()` |
|
||||||
| `#[serde(default="$path")` | Call the path to a function `fn() -> T` to build the value |
|
| `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value |
|
||||||
| `#[serde(skip_serializing)` | Do not serialize this value |
|
| `#[serde(skip_serializing)]` | Do not serialize this value |
|
||||||
| `#[serde(skip_serializing_if="$path")` | Do not serialize this value if this function `fn(&T) -> bool` returns `false` |
|
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
|
||||||
| `#[serde(serialize_with="$path")` | Call a function `fn<T, S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value |
|
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
|
||||||
| `#[serde(deserialize_with="$path")` | Call a function `fn<T, D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value |
|
| `#[serde(serialize_with="$path")]` | Call a function `fn<S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value of type `T` |
|
||||||
|
| `#[serde(deserialize_with="$path")]` | Call a function `fn<D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value of type `T` |
|
||||||
|
|
||||||
|
Upgrading from Serde 0.6
|
||||||
|
========================
|
||||||
|
|
||||||
|
* `#[serde(skip_serializing_if_none)]` was replaced with `#[serde(skip_serializing_if="Option::is_none")]`.
|
||||||
|
* `#[serde(skip_serializing_if_empty)]` was replaced with `#[serde(skip_serializing_if="Vec::is_empty")]`.
|
||||||
|
|
||||||
Serialization Formats Using Serde
|
Serialization Formats Using Serde
|
||||||
=================================
|
=================================
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ default = ["serde_codegen"]
|
|||||||
nightly = ["serde_macros"]
|
nightly = ["serde_macros"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
serde_codegen = { version = "^0.6.4", optional = true }
|
serde_codegen = { version = "^0.7.5", optional = true }
|
||||||
syntex = "^0.22.0"
|
syntex = "^0.32.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = "^0.6.1"
|
serde = "^0.7.5"
|
||||||
serde_json = "^0.6.0"
|
serde_json = "^0.7.0"
|
||||||
serde_macros = { version = "^0.6.1", optional = true }
|
serde_macros = { version = "^0.7.5", optional = true }
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "0.7.0"
|
version = "0.7.5"
|
||||||
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"
|
||||||
repository = "https://github.com/serde-rs/serde"
|
repository = "https://github.com/serde-rs/serde"
|
||||||
documentation = "https://serde-rs.github.io/serde/serde/serde/index.html"
|
documentation = "https://serde-rs.github.io/serde/serde/"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
keywords = ["serde", "serialization"]
|
keywords = ["serde", "serialization"]
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ impl<'a> ser::Serialize for Bytes<'a> {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
|
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
|
||||||
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct ByteBuf {
|
pub struct ByteBuf {
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
// Extracted from https://github.com/rust-num/num.
|
// Extracted from https://github.com/rust-num/num.
|
||||||
|
|
||||||
|
// Rust 1.5 is unhappy that this private module is undocumented.
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use std::{usize, u8, u16, u32, u64};
|
use std::{usize, u8, u16, u32, u64};
|
||||||
use std::{isize, i8, i16, i32, i64};
|
use std::{isize, i8, i16, i32, i64};
|
||||||
use std::{f32, f64};
|
use std::{f32, f64};
|
||||||
|
|||||||
@@ -881,6 +881,15 @@ impl<T: Deserialize> Deserialize for Box<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Deserialize> Deserialize for Box<[T]> {
|
||||||
|
fn deserialize<D>(deserializer: &mut D) -> Result<Box<[T]>, D::Error>
|
||||||
|
where D: Deserializer,
|
||||||
|
{
|
||||||
|
let v: Vec<T> = try!(Deserialize::deserialize(deserializer));
|
||||||
|
Ok(v.into_boxed_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Deserialize> Deserialize for Arc<T> {
|
impl<T: Deserialize> Deserialize for Arc<T> {
|
||||||
fn deserialize<D>(deserializer: &mut D) -> Result<Arc<T>, D::Error>
|
fn deserialize<D>(deserializer: &mut D) -> Result<Arc<T>, D::Error>
|
||||||
where D: Deserializer,
|
where D: Deserializer,
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ pub trait Error: Sized + error::Error {
|
|||||||
fn missing_field(field: &'static str) -> Self {
|
fn missing_field(field: &'static str) -> Self {
|
||||||
Error::custom(format!("Missing field `{}`", field))
|
Error::custom(format!("Missing field `{}`", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raised when a `Deserialize` struct type received more than one of the
|
||||||
|
/// same struct field.
|
||||||
|
fn duplicate_field(field: &'static str) -> Self {
|
||||||
|
Error::custom(format!("Duplicate field `{}`", field))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Type` represents all the primitive types that can be deserialized. This is used by
|
/// `Type` represents all the primitive types that can be deserialized. This is used by
|
||||||
|
|||||||
+10
-10
@@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_codegen"
|
name = "serde_codegen"
|
||||||
version = "0.7.0"
|
version = "0.7.5"
|
||||||
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"
|
||||||
repository = "https://github.com/serde-rs/serde"
|
repository = "https://github.com/serde-rs/serde"
|
||||||
documentation = "https://serde-rs.github.io/serde/serde_codegen/serde_codegen/index.html"
|
documentation = "https://github.com/serde-rs/serde"
|
||||||
build = "build.rs"
|
|
||||||
keywords = ["serde", "serialization"]
|
keywords = ["serde", "serialization"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["with-syntex"]
|
default = ["with-syntex"]
|
||||||
@@ -16,13 +16,13 @@ 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.7.0", optional = true }
|
quasi_codegen = { version = "^0.10.0", optional = true }
|
||||||
syntex = { version = "^0.29.0", optional = true }
|
syntex = { version = "^0.32.0", optional = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aster = { version = "^0.13.1", default-features = false }
|
aster = { version = "^0.16.0", default-features = false }
|
||||||
clippy = { version = "^0.*", optional = true }
|
clippy = { version = "^0.*", optional = true }
|
||||||
quasi = { version = "^0.7.0", default-features = false }
|
quasi = { version = "^0.10.0", default-features = false }
|
||||||
quasi_macros = { version = "^0.7.0", optional = true }
|
quasi_macros = { version = "^0.10.0", optional = true }
|
||||||
syntex = { version = "^0.29.0", optional = true }
|
syntex = { version = "^0.32.0", optional = true }
|
||||||
syntex_syntax = { version = "^0.29.0", optional = true }
|
syntex_syntax = { version = "^0.32.0", optional = true }
|
||||||
|
|||||||
+47
-86
@@ -4,7 +4,7 @@ use syntax::attr;
|
|||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::fold::Folder;
|
use syntax::fold::Folder;
|
||||||
use syntax::parse::parser::PathParsingMode;
|
use syntax::parse::parser::PathStyle;
|
||||||
use syntax::parse::token::{self, InternedString};
|
use syntax::parse::token::{self, InternedString};
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::print::pprust::{lit_to_string, meta_item_to_string};
|
use syntax::print::pprust::{lit_to_string, meta_item_to_string};
|
||||||
@@ -30,11 +30,6 @@ impl Name {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the string expression of the field ident.
|
|
||||||
pub fn ident_expr(&self) -> P<ast::Expr> {
|
|
||||||
AstBuilder::new().expr().str(self.ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the container name for the container when serializing.
|
/// Return the container name for the container when serializing.
|
||||||
pub fn serialize_name(&self) -> InternedString {
|
pub fn serialize_name(&self) -> InternedString {
|
||||||
match self.serialize_name {
|
match self.serialize_name {
|
||||||
@@ -181,10 +176,11 @@ impl VariantAttrs {
|
|||||||
pub struct FieldAttrs {
|
pub struct FieldAttrs {
|
||||||
name: Name,
|
name: Name,
|
||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
|
skip_deserializing_field: bool,
|
||||||
skip_serializing_field_if: Option<P<ast::Expr>>,
|
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||||
serialize_with: Option<P<ast::Expr>>,
|
serialize_with: Option<P<ast::Expr>>,
|
||||||
deserialize_with: Option<P<ast::Expr>>,
|
deserialize_with: Option<ast::Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldAttrs {
|
impl FieldAttrs {
|
||||||
@@ -196,7 +192,7 @@ impl FieldAttrs {
|
|||||||
is_enum: bool) -> Result<Self, Error> {
|
is_enum: bool) -> Result<Self, Error> {
|
||||||
let builder = AstBuilder::new();
|
let builder = AstBuilder::new();
|
||||||
|
|
||||||
let field_ident = match field.node.ident() {
|
let field_ident = match field.ident {
|
||||||
Some(ident) => ident,
|
Some(ident) => ident,
|
||||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||||
};
|
};
|
||||||
@@ -204,13 +200,14 @@ impl FieldAttrs {
|
|||||||
let mut field_attrs = FieldAttrs {
|
let mut field_attrs = FieldAttrs {
|
||||||
name: Name::new(field_ident),
|
name: Name::new(field_ident),
|
||||||
skip_serializing_field: false,
|
skip_serializing_field: false,
|
||||||
|
skip_deserializing_field: false,
|
||||||
skip_serializing_field_if: None,
|
skip_serializing_field_if: None,
|
||||||
default_expr_if_missing: None,
|
default_expr_if_missing: None,
|
||||||
serialize_with: None,
|
serialize_with: None,
|
||||||
deserialize_with: None,
|
deserialize_with: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
match meta_item.node {
|
match meta_item.node {
|
||||||
// Parse `#[serde(rename="foo")]`
|
// Parse `#[serde(rename="foo")]`
|
||||||
@@ -249,6 +246,18 @@ impl FieldAttrs {
|
|||||||
field_attrs.skip_serializing_field = true;
|
field_attrs.skip_serializing_field = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(skip_deserializing)]`
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => {
|
||||||
|
field_attrs.skip_deserializing_field = true;
|
||||||
|
|
||||||
|
// Initialize field to Default::default() unless a different
|
||||||
|
// default is specified by `#[serde(default="...")]`
|
||||||
|
if field_attrs.default_expr_if_missing.is_none() {
|
||||||
|
let default_expr = builder.expr().default();
|
||||||
|
field_attrs.default_expr_if_missing = Some(default_expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if="...")]`
|
// Parse `#[serde(skip_serializing_if="...")]`
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
||||||
let expr = wrap_skip_serializing(
|
let expr = wrap_skip_serializing(
|
||||||
@@ -276,14 +285,8 @@ impl FieldAttrs {
|
|||||||
|
|
||||||
// Parse `#[serde(deserialize_with="...")]`
|
// Parse `#[serde(deserialize_with="...")]`
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
|
||||||
let expr = wrap_deserialize_with(
|
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||||
cx,
|
field_attrs.deserialize_with = Some(path);
|
||||||
&field.node.ty,
|
|
||||||
generics,
|
|
||||||
try!(parse_lit_into_path(cx, name, lit)),
|
|
||||||
);
|
|
||||||
|
|
||||||
field_attrs.deserialize_with = Some(expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@@ -305,35 +308,27 @@ impl FieldAttrs {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate for using a field's default value
|
|
||||||
pub fn expr_is_missing(&self) -> P<ast::Expr> {
|
|
||||||
match self.default_expr_if_missing {
|
|
||||||
Some(ref expr) => expr.clone(),
|
|
||||||
None => {
|
|
||||||
let name = self.name.ident_expr();
|
|
||||||
AstBuilder::new().expr()
|
|
||||||
.try()
|
|
||||||
.method_call("missing_field").id("visitor")
|
|
||||||
.with_arg(name)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate for ignoring a field when serializing a value
|
|
||||||
pub fn skip_serializing_field(&self) -> bool {
|
pub fn skip_serializing_field(&self) -> bool {
|
||||||
self.skip_serializing_field
|
self.skip_serializing_field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_deserializing_field(&self) -> bool {
|
||||||
|
self.skip_deserializing_field
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
||||||
self.skip_serializing_field_if.as_ref()
|
self.skip_serializing_field_if.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_expr_if_missing(&self) -> Option<&P<ast::Expr>> {
|
||||||
|
self.default_expr_if_missing.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||||
self.serialize_with.as_ref()
|
self.serialize_with.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_with(&self) -> Option<&P<ast::Expr>> {
|
pub fn deserialize_with(&self) -> Option<&ast::Path> {
|
||||||
self.deserialize_with.as_ref()
|
self.deserialize_with.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,7 +377,7 @@ fn get_renames(cx: &ExtCtxt,
|
|||||||
Ok((ser_name, de_name))
|
Ok((ser_name, de_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
||||||
match attr.node.value.node {
|
match attr.node.value.node {
|
||||||
ast::MetaItemKind::List(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);
|
||||||
@@ -462,18 +457,18 @@ fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::
|
|||||||
// error reporting, we'll first parse the string into a token tree. Then we'll update those
|
// error reporting, we'll first parse the string into a token tree. Then we'll update those
|
||||||
// spans to say they're coming from a macro context that originally came from the attribute,
|
// spans to say they're coming from a macro context that originally came from the attribute,
|
||||||
// and then finally parse them into an expression.
|
// and then finally parse them into an expression.
|
||||||
let tts = parse::parse_tts_from_source_str(
|
let tts = panictry!(parse::parse_tts_from_source_str(
|
||||||
format!("<serde {} expansion>", name),
|
format!("<serde {} expansion>", name),
|
||||||
(*source).to_owned(),
|
(*source).to_owned(),
|
||||||
cx.cfg(),
|
cx.cfg(),
|
||||||
cx.parse_sess());
|
cx.parse_sess()));
|
||||||
|
|
||||||
// Respan the spans to say they are all coming from this macro.
|
// Respan the spans to say they are all coming from this macro.
|
||||||
let tts = Respanner { cx: cx }.fold_tts(&tts);
|
let tts = Respanner { cx: cx }.fold_tts(&tts);
|
||||||
|
|
||||||
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts);
|
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts);
|
||||||
|
|
||||||
let path = match parser.parse_path(PathParsingMode::LifetimeAndTypesWithoutColons) {
|
let path = match parser.parse_path(PathStyle::Type) {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(mut e) => {
|
Err(mut e) => {
|
||||||
e.emit();
|
e.emit();
|
||||||
@@ -556,37 +551,37 @@ fn wrap_serialize_with(cx: &ExtCtxt,
|
|||||||
|
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
trait __SerdeSerializeWith {
|
trait __SerdeSerializeWith {
|
||||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||||
where S: ::serde::ser::Serializer;
|
where __S: _serde::ser::Serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> __SerdeSerializeWith for &'a T
|
impl<'__a, __T> __SerdeSerializeWith for &'__a __T
|
||||||
where T: 'a + __SerdeSerializeWith,
|
where __T: '__a + __SerdeSerializeWith,
|
||||||
{
|
{
|
||||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||||
where S: ::serde::ser::Serializer
|
where __S: _serde::ser::Serializer
|
||||||
{
|
{
|
||||||
(**self).__serde_serialize_with(serializer)
|
(**self).__serde_serialize_with(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $generics __SerdeSerializeWith for $container_ty $where_clause {
|
impl $generics __SerdeSerializeWith for $container_ty $where_clause {
|
||||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||||
where S: ::serde::ser::Serializer
|
where __S: _serde::ser::Serializer
|
||||||
{
|
{
|
||||||
$expr
|
$expr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct __SerdeSerializeWithStruct<'a, T: 'a> {
|
struct __SerdeSerializeWithStruct<'__a, __T: '__a> {
|
||||||
value: &'a T,
|
value: &'__a __T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> ::serde::ser::Serialize for __SerdeSerializeWithStruct<'a, T>
|
impl<'__a, __T> _serde::ser::Serialize for __SerdeSerializeWithStruct<'__a, __T>
|
||||||
where T: 'a + __SerdeSerializeWith
|
where __T: '__a + __SerdeSerializeWith
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn serialize<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||||
where S: ::serde::ser::Serializer
|
where __S: _serde::ser::Serializer
|
||||||
{
|
{
|
||||||
self.value.__serde_serialize_with(serializer)
|
self.value.__serde_serialize_with(serializer)
|
||||||
}
|
}
|
||||||
@@ -597,37 +592,3 @@ fn wrap_serialize_with(cx: &ExtCtxt,
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in a trait to prevent
|
|
||||||
/// it from accessing the internal `Deserialize` state.
|
|
||||||
fn wrap_deserialize_with(cx: &ExtCtxt,
|
|
||||||
field_ty: &P<ast::Ty>,
|
|
||||||
generics: &ast::Generics,
|
|
||||||
path: ast::Path) -> P<ast::Expr> {
|
|
||||||
// Quasi-quoting doesn't do a great job of expanding generics into paths, so manually build it.
|
|
||||||
let ty_path = AstBuilder::new().path()
|
|
||||||
.segment("__SerdeDeserializeWithStruct")
|
|
||||||
.with_generics(generics.clone())
|
|
||||||
.build()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let where_clause = &generics.where_clause;
|
|
||||||
|
|
||||||
quote_expr!(cx, {
|
|
||||||
struct __SerdeDeserializeWithStruct $generics $where_clause {
|
|
||||||
value: $field_ty,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $generics ::serde::de::Deserialize for $ty_path $where_clause {
|
|
||||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
|
||||||
where D: ::serde::de::Deserializer
|
|
||||||
{
|
|
||||||
let value = try!($path(deserializer));
|
|
||||||
Ok(__SerdeDeserializeWithStruct { value: value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let value: $ty_path = try!(visitor.visit_value());
|
|
||||||
Ok(value.value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use aster::AstBuilder;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::ext::base::ExtCtxt;
|
||||||
|
use syntax::ptr::P;
|
||||||
|
use syntax::visit;
|
||||||
|
|
||||||
|
// Remove the default from every type parameter because in the generated impls
|
||||||
|
// they look like associated types: "error: associated type bindings are not
|
||||||
|
// allowed here".
|
||||||
|
pub fn without_defaults(generics: &ast::Generics) -> ast::Generics {
|
||||||
|
ast::Generics {
|
||||||
|
ty_params: generics.ty_params.iter().map(|ty_param| {
|
||||||
|
ast::TyParam {
|
||||||
|
default: None,
|
||||||
|
.. ty_param.clone()
|
||||||
|
}}).collect(),
|
||||||
|
.. generics.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_bound(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &AstBuilder,
|
||||||
|
item: &ast::Item,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
filter: &Fn(&ast::StructField) -> bool,
|
||||||
|
bound: &ast::Path,
|
||||||
|
) -> ast::Generics {
|
||||||
|
builder.from_generics(generics.clone())
|
||||||
|
.with_predicates(
|
||||||
|
all_variants(cx, item).iter()
|
||||||
|
.flat_map(|variant_data| all_struct_fields(variant_data))
|
||||||
|
.filter(|field| filter(field))
|
||||||
|
.map(|field| &field.ty)
|
||||||
|
// TODO this filter can be removed later, see comment on function
|
||||||
|
.filter(|ty| contains_generic(ty, generics))
|
||||||
|
.map(|ty| strip_reference(ty))
|
||||||
|
.map(|ty| builder.where_predicate()
|
||||||
|
// the type that is being bounded e.g. T
|
||||||
|
.bound().build(ty.clone())
|
||||||
|
// the bound e.g. Serialize
|
||||||
|
.bound().trait_(bound.clone()).build()
|
||||||
|
.build()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_variants<'a>(cx: &ExtCtxt, item: &'a ast::Item) -> Vec<&'a ast::VariantData> {
|
||||||
|
match item.node {
|
||||||
|
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||||
|
vec![variant_data]
|
||||||
|
}
|
||||||
|
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||||
|
enum_def.variants.iter()
|
||||||
|
.map(|variant| &variant.node.data)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cx.span_bug(item.span, "expected Item to be Struct or Enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_struct_fields(variant_data: &ast::VariantData) -> &[ast::StructField] {
|
||||||
|
match *variant_data {
|
||||||
|
ast::VariantData::Struct(ref fields, _) |
|
||||||
|
ast::VariantData::Tuple(ref fields, _) => {
|
||||||
|
fields
|
||||||
|
}
|
||||||
|
ast::VariantData::Unit(_) => {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rust <1.7 enforces that `where` clauses involve generic type parameters. The
|
||||||
|
// corresponding compiler error is E0193. It is no longer enforced in Rust >=1.7
|
||||||
|
// so this filtering can be removed in the future when we stop supporting <1.7.
|
||||||
|
//
|
||||||
|
// E0193 means we must not generate a `where` clause like `i32: Serialize`
|
||||||
|
// because even though i32 implements Serialize, i32 is not a generic type
|
||||||
|
// parameter. Clauses like `T: Serialize` and `Option<T>: Serialize` are okay.
|
||||||
|
// This function decides whether a given type references any of the generic type
|
||||||
|
// parameters in the input `Generics`.
|
||||||
|
fn contains_generic(ty: &ast::Ty, generics: &ast::Generics) -> bool {
|
||||||
|
struct FindGeneric<'a> {
|
||||||
|
generic_names: &'a HashSet<ast::Name>,
|
||||||
|
found_generic: bool,
|
||||||
|
}
|
||||||
|
impl<'a, 'v> visit::Visitor<'v> for FindGeneric<'a> {
|
||||||
|
fn visit_path(&mut self, path: &'v ast::Path, _id: ast::NodeId) {
|
||||||
|
if !path.global
|
||||||
|
&& path.segments.len() == 1
|
||||||
|
&& self.generic_names.contains(&path.segments[0].identifier.name) {
|
||||||
|
self.found_generic = true;
|
||||||
|
} else {
|
||||||
|
visit::walk_path(self, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let generic_names: HashSet<_> = generics.ty_params.iter()
|
||||||
|
.map(|ty_param| ty_param.ident.name)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut visitor = FindGeneric {
|
||||||
|
generic_names: &generic_names,
|
||||||
|
found_generic: false,
|
||||||
|
};
|
||||||
|
visit::walk_ty(&mut visitor, ty);
|
||||||
|
visitor.found_generic
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is required to handle types that use both a reference and a value of
|
||||||
|
// the same type, as in:
|
||||||
|
//
|
||||||
|
// enum Test<'a, T> where T: 'a {
|
||||||
|
// Lifetime(&'a T),
|
||||||
|
// NoLifetime(T),
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Preserving references, we would generate an impl like:
|
||||||
|
//
|
||||||
|
// impl<'a, T> Serialize for Test<'a, T>
|
||||||
|
// where &'a T: Serialize,
|
||||||
|
// T: Serialize { ... }
|
||||||
|
//
|
||||||
|
// And taking a reference to one of the elements would fail with:
|
||||||
|
//
|
||||||
|
// error: cannot infer an appropriate lifetime for pattern due
|
||||||
|
// to conflicting requirements [E0495]
|
||||||
|
// Test::NoLifetime(ref v) => { ... }
|
||||||
|
// ^~~~~
|
||||||
|
//
|
||||||
|
// Instead, we strip references before adding `T: Serialize` bounds in order to
|
||||||
|
// generate:
|
||||||
|
//
|
||||||
|
// impl<'a, T> Serialize for Test<'a, T>
|
||||||
|
// where T: Serialize { ... }
|
||||||
|
fn strip_reference(ty: &P<ast::Ty>) -> &P<ast::Ty> {
|
||||||
|
match ty.node {
|
||||||
|
ast::TyKind::Rptr(_, ref mut_ty) => &mut_ty.ty,
|
||||||
|
_ => ty
|
||||||
|
}
|
||||||
|
}
|
||||||
+360
-154
@@ -14,6 +14,7 @@ use syntax::parse::token::InternedString;
|
|||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use attr;
|
use attr;
|
||||||
|
use bound;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
pub fn expand_derive_deserialize(
|
pub fn expand_derive_deserialize(
|
||||||
@@ -46,11 +47,7 @@ pub fn expand_derive_deserialize(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let impl_generics = builder.from_generics(generics.clone())
|
let impl_generics = build_impl_generics(cx, &builder, item, generics);
|
||||||
.add_ty_param_bound(
|
|
||||||
builder.path().global().ids(&["serde", "de", "Deserialize"]).build()
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let ty = builder.ty().path()
|
let ty = builder.ty().path()
|
||||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||||
@@ -66,19 +63,88 @@ pub fn expand_derive_deserialize(
|
|||||||
|
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
|
let dummy_const = builder.id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident));
|
||||||
|
|
||||||
let impl_item = quote_item!(cx,
|
let impl_item = quote_item!(cx,
|
||||||
impl $impl_generics ::serde::de::Deserialize for $ty $where_clause {
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<$ty, __D::Error>
|
const $dummy_const: () = {
|
||||||
where __D: ::serde::de::Deserializer,
|
extern crate serde as _serde;
|
||||||
{
|
#[automatically_derived]
|
||||||
$body
|
impl $impl_generics _serde::de::Deserialize for $ty $where_clause {
|
||||||
|
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<$ty, __D::Error>
|
||||||
|
where __D: _serde::de::Deserializer,
|
||||||
|
{
|
||||||
|
$body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
push(Annotatable::Item(impl_item))
|
push(Annotatable::Item(impl_item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All the generics in the input, plus a bound `T: Deserialize` for each generic
|
||||||
|
// field type that will be deserialized by us, plus a bound `T: Default` for
|
||||||
|
// each generic field type that will be set to a default value.
|
||||||
|
fn build_impl_generics(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
) -> ast::Generics {
|
||||||
|
let generics = bound::without_defaults(generics);
|
||||||
|
let generics = bound::with_bound(cx, builder, item, &generics,
|
||||||
|
&deserialized_by_us,
|
||||||
|
&builder.path().ids(&["_serde", "de", "Deserialize"]).build());
|
||||||
|
let generics = bound::with_bound(cx, builder, item, &generics,
|
||||||
|
&requires_default,
|
||||||
|
&builder.path().global().ids(&["std", "default", "Default"]).build());
|
||||||
|
generics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields with a `skip_deserializing` or `deserialize_with` attribute are not
|
||||||
|
// deserialized by us. All other fields may need a `T: Deserialize` bound where
|
||||||
|
// T is the type of the field.
|
||||||
|
fn deserialized_by_us(field: &ast::StructField) -> bool {
|
||||||
|
for meta_items in field.attrs.iter().filter_map(attr::get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::NameValue(ref name, _) if name == &"deserialize_with" => {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||||
|
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||||
|
fn requires_default(field: &ast::StructField) -> bool {
|
||||||
|
let mut has_skip_deserializing = false;
|
||||||
|
for meta_items in field.attrs.iter().filter_map(attr::get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::NameValue(ref name, _) if name == &"default" => {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => {
|
||||||
|
has_skip_deserializing = true
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has_skip_deserializing
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_body(
|
fn deserialize_body(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
@@ -148,7 +214,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.ident.is_some()) {
|
||||||
cx.span_bug(span, "tuple struct has named fields")
|
cx.span_bug(span, "tuple struct has named fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +229,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.ident.is_none()) {
|
||||||
cx.span_bug(span, "struct has unnamed fields")
|
cx.span_bug(span, "struct has unnamed fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,8 +315,7 @@ fn deserialize_visitor(
|
|||||||
fn deserializer_ty_param(builder: &aster::AstBuilder) -> ast::TyParam {
|
fn deserializer_ty_param(builder: &aster::AstBuilder) -> ast::TyParam {
|
||||||
builder.ty_param("__D")
|
builder.ty_param("__D")
|
||||||
.trait_bound(builder.path()
|
.trait_bound(builder.path()
|
||||||
.global()
|
.segment("_serde").build()
|
||||||
.segment("serde").build()
|
|
||||||
.segment("de").build()
|
.segment("de").build()
|
||||||
.id("Deserializer")
|
.id("Deserializer")
|
||||||
.build())
|
.build())
|
||||||
@@ -272,19 +337,19 @@ fn deserialize_unit_struct(
|
|||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
struct __Visitor;
|
struct __Visitor;
|
||||||
|
|
||||||
impl ::serde::de::Visitor for __Visitor {
|
impl _serde::de::Visitor for __Visitor {
|
||||||
type Value = $type_ident;
|
type Value = $type_ident;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_unit<E>(&mut self) -> ::std::result::Result<$type_ident, E>
|
fn visit_unit<__E>(&mut self) -> ::std::result::Result<$type_ident, __E>
|
||||||
where E: ::serde::de::Error,
|
where __E: _serde::de::Error,
|
||||||
{
|
{
|
||||||
Ok($type_ident)
|
Ok($type_ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<V>(&mut self, mut visitor: V) -> ::std::result::Result<$type_ident, V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$type_ident, __V::Error>
|
||||||
where V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
try!(visitor.end());
|
try!(visitor.end());
|
||||||
self.visit_unit()
|
self.visit_unit()
|
||||||
@@ -324,20 +389,20 @@ fn deserialize_newtype_struct(
|
|||||||
Ok(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 {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_newtype_struct<D>(&mut self, deserializer: &mut D) -> ::std::result::Result<Self::Value, D::Error>
|
fn visit_newtype_struct<__E>(&mut self, deserializer: &mut __E) -> ::std::result::Result<Self::Value, __E::Error>
|
||||||
where D: ::serde::de::Deserializer,
|
where __E: _serde::de::Deserializer,
|
||||||
{
|
{
|
||||||
let value = try!(::serde::de::Deserialize::deserialize(deserializer));
|
let value = try!(_serde::de::Deserialize::deserialize(deserializer));
|
||||||
Ok($type_ident(value))
|
Ok($type_ident(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
$visit_seq_expr
|
$visit_seq_expr
|
||||||
}
|
}
|
||||||
@@ -377,12 +442,12 @@ fn deserialize_tuple_struct(
|
|||||||
Ok(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 {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
$visit_seq_expr
|
$visit_seq_expr
|
||||||
}
|
}
|
||||||
@@ -405,7 +470,7 @@ fn deserialize_seq(
|
|||||||
let $name = match try!(visitor.visit()) {
|
let $name = match try!(visitor.visit()) {
|
||||||
Some(value) => { value },
|
Some(value) => { value },
|
||||||
None => {
|
None => {
|
||||||
return Err(::serde::de::Error::end_of_stream());
|
return Err(_serde::de::Error::end_of_stream());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
).unwrap()
|
).unwrap()
|
||||||
@@ -429,20 +494,45 @@ fn deserialize_seq(
|
|||||||
fn deserialize_struct_as_seq(
|
fn deserialize_struct_as_seq(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
impl_generics: &ast::Generics,
|
||||||
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let let_values: Vec<_> = (0 .. fields.len())
|
let let_values: Vec<_> = fields.iter()
|
||||||
.map(|i| {
|
.enumerate()
|
||||||
|
.map(|(i, &(field, ref attrs))| {
|
||||||
let name = builder.id(format!("__field{}", i));
|
let name = builder.id(format!("__field{}", i));
|
||||||
quote_stmt!(cx,
|
if attrs.skip_deserializing_field() {
|
||||||
let $name = match try!(visitor.visit()) {
|
let default = expr_is_missing(cx, attrs);
|
||||||
Some(value) => { value },
|
quote_stmt!(cx,
|
||||||
|
let $name = $default;
|
||||||
|
).unwrap()
|
||||||
|
} else {
|
||||||
|
let visit = match attrs.deserialize_with() {
|
||||||
None => {
|
None => {
|
||||||
return Err(::serde::de::Error::end_of_stream());
|
let field_ty = &field.ty;
|
||||||
|
quote_expr!(cx, try!(visitor.visit::<$field_ty>()))
|
||||||
|
}
|
||||||
|
Some(path) => {
|
||||||
|
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
|
||||||
|
cx, builder, type_ident, impl_generics, &field.ty, path);
|
||||||
|
quote_expr!(cx, {
|
||||||
|
$wrapper
|
||||||
|
$wrapper_impl
|
||||||
|
try!(visitor.visit::<$wrapper_ty>()).map(|wrap| wrap.value)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
).unwrap()
|
quote_stmt!(cx,
|
||||||
|
let $name = match $visit {
|
||||||
|
Some(value) => { value },
|
||||||
|
None => {
|
||||||
|
return Err(_serde::de::Error::end_of_stream());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
).unwrap()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -450,11 +540,11 @@ fn deserialize_struct_as_seq(
|
|||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
fields.iter()
|
fields.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, field)| {
|
.map(|(i, &(field, _))| {
|
||||||
(
|
(
|
||||||
match field.node.kind {
|
match field.ident {
|
||||||
ast::NamedField(name, _) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
ast::UnnamedField(_) => {
|
None => {
|
||||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -493,22 +583,25 @@ fn deserialize_struct(
|
|||||||
|
|
||||||
let type_path = builder.path().id(type_ident).build();
|
let type_path = builder.path().id(type_ident).build();
|
||||||
|
|
||||||
|
let fields_with_attrs = try!(fields_with_attrs(cx, impl_generics, &ty, fields, false));
|
||||||
|
|
||||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
type_ident,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
fields,
|
impl_generics,
|
||||||
|
&fields_with_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
type_ident,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
&ty,
|
|
||||||
impl_generics,
|
impl_generics,
|
||||||
fields,
|
&fields_with_attrs,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
false,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = container_attrs.name().deserialize_name_expr();
|
let type_name = container_attrs.name().deserialize_name_expr();
|
||||||
@@ -518,19 +611,19 @@ fn deserialize_struct(
|
|||||||
|
|
||||||
$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 {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
$visit_seq_expr
|
$visit_seq_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::MapVisitor,
|
where __V: _serde::de::MapVisitor,
|
||||||
{
|
{
|
||||||
$visit_map_expr
|
$visit_map_expr
|
||||||
}
|
}
|
||||||
@@ -583,10 +676,10 @@ fn deserialize_item_enum(
|
|||||||
const VARIANTS: &'static [&'static str] = $variants_expr;
|
const VARIANTS: &'static [&'static str] = $variants_expr;
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let ignored_arm = if !container_attrs.deny_unknown_fields() {
|
let ignored_arm = if container_attrs.deny_unknown_fields() {
|
||||||
Some(quote_arm!(cx, __Field::__ignore => { Err(::serde::de::Error::end_of_stream()) }))
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(quote_arm!(cx, __Field::__ignore => { Err(_serde::de::Error::end_of_stream()) }))
|
||||||
};
|
};
|
||||||
|
|
||||||
// Match arms to extract a variant from a string
|
// Match arms to extract a variant from a string
|
||||||
@@ -623,11 +716,11 @@ fn deserialize_item_enum(
|
|||||||
|
|
||||||
$visitor_item
|
$visitor_item
|
||||||
|
|
||||||
impl $visitor_generics ::serde::de::EnumVisitor for $visitor_ty $where_clause {
|
impl $visitor_generics _serde::de::EnumVisitor for $visitor_ty $where_clause {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
fn visit<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::VariantVisitor,
|
where __V: _serde::de::VariantVisitor,
|
||||||
{
|
{
|
||||||
match try!(visitor.visit_variant()) {
|
match try!(visitor.visit_variant()) {
|
||||||
$variant_arms
|
$variant_arms
|
||||||
@@ -719,11 +812,11 @@ fn deserialize_tuple_variant(
|
|||||||
Ok(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 {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
$visit_seq_expr
|
$visit_seq_expr
|
||||||
}
|
}
|
||||||
@@ -750,22 +843,25 @@ fn deserialize_struct_variant(
|
|||||||
.id(variant_ident)
|
.id(variant_ident)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
let fields_with_attrs = try!(fields_with_attrs(cx, generics, &ty, fields, true));
|
||||||
|
|
||||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
type_ident,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
fields,
|
generics,
|
||||||
|
&fields_with_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
type_ident,
|
||||||
type_path,
|
type_path,
|
||||||
&ty,
|
|
||||||
generics,
|
generics,
|
||||||
fields,
|
&fields_with_attrs,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
true,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||||
@@ -780,19 +876,19 @@ fn deserialize_struct_variant(
|
|||||||
|
|
||||||
$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 {
|
||||||
type Value = $ty;
|
type Value = $ty;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::SeqVisitor,
|
where __V: _serde::de::SeqVisitor,
|
||||||
{
|
{
|
||||||
$visit_seq_expr
|
$visit_seq_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::MapVisitor,
|
where __V: _serde::de::MapVisitor,
|
||||||
{
|
{
|
||||||
$field_expr
|
$field_expr
|
||||||
}
|
}
|
||||||
@@ -816,11 +912,11 @@ fn deserialize_field_visitor(
|
|||||||
.map(|i| builder.id(format!("__field{}", i)))
|
.map(|i| builder.id(format!("__field{}", i)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let ignore_variant = if !container_attrs.deny_unknown_fields() {
|
let ignore_variant = if container_attrs.deny_unknown_fields() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
let skip_ident = builder.id("__ignore");
|
let skip_ident = builder.id("__ignore");
|
||||||
Some(builder.variant(skip_ident).unit())
|
Some(builder.variant(skip_ident).unit())
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let field_enum = builder.item()
|
let field_enum = builder.item()
|
||||||
@@ -851,7 +947,7 @@ fn deserialize_field_visitor(
|
|||||||
quote_expr!(cx, Ok(__Field::__ignore))
|
quote_expr!(cx, Ok(__Field::__ignore))
|
||||||
} else {
|
} else {
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
Err(::serde::de::Error::invalid_value($index_error_msg))
|
Err(_serde::de::Error::invalid_value($index_error_msg))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -877,7 +973,7 @@ fn deserialize_field_visitor(
|
|||||||
let fallthrough_str_arm_expr = if !is_variant && !container_attrs.deny_unknown_fields() {
|
let fallthrough_str_arm_expr = if !is_variant && !container_attrs.deny_unknown_fields() {
|
||||||
quote_expr!(cx, Ok(__Field::__ignore))
|
quote_expr!(cx, Ok(__Field::__ignore))
|
||||||
} else {
|
} else {
|
||||||
quote_expr!(cx, Err(::serde::de::Error::$unknown_ident(value)))
|
quote_expr!(cx, Err(_serde::de::Error::$unknown_ident(value)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let str_body = quote_expr!(cx,
|
let str_body = quote_expr!(cx,
|
||||||
@@ -907,7 +1003,7 @@ fn deserialize_field_visitor(
|
|||||||
} else {
|
} else {
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
let value = ::std::string::String::from_utf8_lossy(value);
|
let value = ::std::string::String::from_utf8_lossy(value);
|
||||||
Err(::serde::de::Error::$unknown_ident(&value))
|
Err(_serde::de::Error::$unknown_ident(&value))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -919,42 +1015,44 @@ fn deserialize_field_visitor(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let impl_item = quote_item!(cx,
|
let impl_item = quote_item!(cx,
|
||||||
impl ::serde::de::Deserialize for __Field {
|
impl _serde::de::Deserialize for __Field {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error>
|
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<__Field, __D::Error>
|
||||||
where D: ::serde::de::Deserializer,
|
where __D: _serde::de::Deserializer,
|
||||||
{
|
{
|
||||||
use std::marker::PhantomData;
|
struct __FieldVisitor<__D> {
|
||||||
|
phantom: ::std::marker::PhantomData<__D>
|
||||||
struct __FieldVisitor<D> {
|
|
||||||
phantom: PhantomData<D>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<__D> ::serde::de::Visitor for __FieldVisitor<__D>
|
impl<__D> _serde::de::Visitor for __FieldVisitor<__D>
|
||||||
where __D: ::serde::de::Deserializer
|
where __D: _serde::de::Deserializer
|
||||||
{
|
{
|
||||||
type Value = __Field;
|
type Value = __Field;
|
||||||
|
|
||||||
fn visit_usize<E>(&mut self, value: usize) -> ::std::result::Result<__Field, E>
|
fn visit_usize<__E>(&mut self, value: usize) -> ::std::result::Result<__Field, __E>
|
||||||
where E: ::serde::de::Error,
|
where __E: _serde::de::Error,
|
||||||
{
|
{
|
||||||
$index_body
|
$index_body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E>
|
fn visit_str<__E>(&mut self, value: &str) -> ::std::result::Result<__Field, __E>
|
||||||
where E: ::serde::de::Error,
|
where __E: _serde::de::Error,
|
||||||
{
|
{
|
||||||
$str_body
|
$str_body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bytes<E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, E>
|
fn visit_bytes<__E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, __E>
|
||||||
where E: ::serde::de::Error,
|
where __E: _serde::de::Error,
|
||||||
{
|
{
|
||||||
$bytes_body
|
$bytes_body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer.deserialize_struct_field(__FieldVisitor::<D>{ phantom: PhantomData })
|
deserializer.deserialize_struct_field(
|
||||||
|
__FieldVisitor::<__D>{
|
||||||
|
phantom: ::std::marker::PhantomData
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap();
|
).unwrap();
|
||||||
@@ -965,30 +1063,20 @@ fn deserialize_field_visitor(
|
|||||||
fn deserialize_struct_visitor(
|
fn deserialize_struct_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
container_ty: &P<ast::Ty>,
|
impl_generics: &ast::Generics,
|
||||||
generics: &ast::Generics,
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
fields: &[ast::StructField],
|
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
is_enum: bool,
|
|
||||||
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
||||||
let field_exprs = fields.iter()
|
let field_exprs = fields.iter()
|
||||||
.map(|field| {
|
.map(|&(_, ref attrs)| attrs.name().deserialize_name())
|
||||||
let field_attrs = try!(
|
|
||||||
attr::FieldAttrs::from_field(cx,
|
|
||||||
container_ty,
|
|
||||||
generics,
|
|
||||||
field,
|
|
||||||
is_enum)
|
|
||||||
);
|
|
||||||
Ok(field_attrs.name().deserialize_name())
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
try!(field_exprs),
|
field_exprs,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -996,21 +1084,20 @@ fn deserialize_struct_visitor(
|
|||||||
let visit_map_expr = try!(deserialize_map(
|
let visit_map_expr = try!(deserialize_map(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
type_ident,
|
||||||
struct_path,
|
struct_path,
|
||||||
container_ty,
|
impl_generics,
|
||||||
generics,
|
|
||||||
fields,
|
fields,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
is_enum,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let fields_expr = builder.expr().ref_().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.ident {
|
||||||
ast::NamedField(name, _) => builder.expr().str(name),
|
Some(name) => builder.expr().str(name),
|
||||||
ast::UnnamedField(_) => {
|
None => {
|
||||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1028,63 +1115,91 @@ fn deserialize_struct_visitor(
|
|||||||
fn deserialize_map(
|
fn deserialize_map(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
container_ty: &P<ast::Ty>,
|
impl_generics: &ast::Generics,
|
||||||
generics: &ast::Generics,
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
fields: &[ast::StructField],
|
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
is_enum: bool,
|
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
let fields_attrs_names = fields.iter()
|
||||||
.map(|i| builder.id(format!("__field{}", i)))
|
.enumerate()
|
||||||
|
.map(|(i, &(ref field, ref attrs))|
|
||||||
|
(field, attrs, builder.id(format!("__field{}", i))))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Declare each field that will be deserialized.
|
||||||
|
let let_values: Vec<ast::Stmt> = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
|
.map(|&(field, _, name)| {
|
||||||
|
let field_ty = &field.ty;
|
||||||
|
quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_attrs: Vec<_> = try!(
|
|
||||||
fields.iter()
|
|
||||||
.map(|field| attr::FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
|
||||||
.collect()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Declare each field.
|
|
||||||
let let_values: Vec<ast::Stmt> = field_names.iter()
|
|
||||||
.map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
|
|
||||||
// Visit ignored values to consume them
|
|
||||||
let ignored_arm = if !container_attrs.deny_unknown_fields() {
|
|
||||||
Some(quote_arm!(cx,
|
|
||||||
_ => { try!(visitor.visit_value::<::serde::de::impls::IgnoredAny>()); }
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Match arms to extract a value for a field.
|
// Match arms to extract a value for a field.
|
||||||
let value_arms = field_attrs.iter().zip(field_names.iter())
|
let value_arms = fields_attrs_names.iter()
|
||||||
.map(|(field_attr, field_name)| {
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
let expr = match field_attr.deserialize_with() {
|
.map(|&(field, ref attrs, name)| {
|
||||||
Some(expr) => expr.clone(),
|
let deser_name = attrs.name().deserialize_name();
|
||||||
None => quote_expr!(cx, visitor.visit_value()),
|
let name_str = builder.expr().lit().str(deser_name);
|
||||||
};
|
|
||||||
|
|
||||||
|
let visit = match attrs.deserialize_with() {
|
||||||
|
None => {
|
||||||
|
let field_ty = &field.ty;
|
||||||
|
quote_expr!(cx, try!(visitor.visit_value::<$field_ty>()))
|
||||||
|
}
|
||||||
|
Some(path) => {
|
||||||
|
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
|
||||||
|
cx, builder, type_ident, impl_generics, &field.ty, path);
|
||||||
|
quote_expr!(cx, ({
|
||||||
|
$wrapper
|
||||||
|
$wrapper_impl
|
||||||
|
try!(visitor.visit_value::<$wrapper_ty>()).value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
__Field::$field_name => {
|
__Field::$name => {
|
||||||
$field_name = Some(try!($expr));
|
if $name.is_some() {
|
||||||
|
return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str));
|
||||||
|
}
|
||||||
|
$name = Some($visit);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.chain(ignored_arm.into_iter())
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let extract_values = field_attrs.iter().zip(field_names.iter())
|
// Match arms to ignore value for fields that have `skip_deserializing`.
|
||||||
.map(|(field_attr, field_name)| {
|
// Ignored even if `deny_unknown_fields` is set.
|
||||||
let missing_expr = field_attr.expr_is_missing();
|
let skipped_arms = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| attrs.skip_deserializing_field())
|
||||||
|
.map(|&(_, _, name)| {
|
||||||
|
quote_arm!(cx,
|
||||||
|
__Field::$name => {
|
||||||
|
try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Visit ignored values to consume them
|
||||||
|
let ignored_arm = if container_attrs.deny_unknown_fields() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(quote_arm!(cx,
|
||||||
|
_ => { try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>()); }
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
let extract_values = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
|
.map(|&(_, ref attrs, name)| {
|
||||||
|
let missing_expr = expr_is_missing(cx, attrs);
|
||||||
|
|
||||||
Ok(quote_stmt!(cx,
|
Ok(quote_stmt!(cx,
|
||||||
let $field_name = match $field_name {
|
let $name = match $name {
|
||||||
Some($field_name) => $field_name,
|
Some($name) => $name,
|
||||||
None => $missing_expr
|
None => $missing_expr
|
||||||
};
|
};
|
||||||
).unwrap())
|
).unwrap())
|
||||||
@@ -1095,17 +1210,20 @@ fn deserialize_map(
|
|||||||
|
|
||||||
let result = builder.expr().struct_path(struct_path)
|
let result = builder.expr().struct_path(struct_path)
|
||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
fields.iter()
|
fields_attrs_names.iter()
|
||||||
.zip(field_names.iter())
|
.map(|&(field, attrs, name)| {
|
||||||
.map(|(field, field_name)| {
|
|
||||||
(
|
(
|
||||||
match field.node.kind {
|
match field.ident {
|
||||||
ast::NamedField(name, _) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
ast::UnnamedField(_) => {
|
None => {
|
||||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder.expr().id(field_name),
|
if attrs.skip_deserializing_field() {
|
||||||
|
expr_is_missing(cx, attrs)
|
||||||
|
} else {
|
||||||
|
builder.expr().id(name)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -1114,9 +1232,11 @@ fn deserialize_map(
|
|||||||
Ok(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::<__Field>()) {
|
||||||
match key {
|
match key {
|
||||||
$value_arms
|
$value_arms
|
||||||
|
$skipped_arms
|
||||||
|
$ignored_arm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1127,3 +1247,89 @@ fn deserialize_map(
|
|||||||
Ok($result)
|
Ok($result)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fields_with_attrs<'a>(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
ty: &P<ast::Ty>,
|
||||||
|
fields: &'a [ast::StructField],
|
||||||
|
is_enum: bool
|
||||||
|
) -> Result<Vec<(&'a ast::StructField, attr::FieldAttrs)>, Error> {
|
||||||
|
fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let attrs = try!(attr::FieldAttrs::from_field(cx, &ty, generics, field, is_enum));
|
||||||
|
Ok((field, attrs))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in
|
||||||
|
/// a trait to prevent it from accessing the internal `Deserialize` state.
|
||||||
|
fn wrap_deserialize_with(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
|
impl_generics: &ast::Generics,
|
||||||
|
field_ty: &P<ast::Ty>,
|
||||||
|
deserialize_with: &ast::Path,
|
||||||
|
) -> (ast::Stmt, ast::Stmt, ast::Path) {
|
||||||
|
// Quasi-quoting doesn't do a great job of expanding generics into paths,
|
||||||
|
// so manually build it.
|
||||||
|
let wrapper_ty = builder.path()
|
||||||
|
.segment("__SerdeDeserializeWithStruct")
|
||||||
|
.with_generics(impl_generics.clone())
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
|
let phantom_ty = builder.path()
|
||||||
|
.segment(type_ident)
|
||||||
|
.with_generics(builder.from_generics(impl_generics.clone())
|
||||||
|
.strip_ty_params()
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
(
|
||||||
|
quote_stmt!(cx,
|
||||||
|
struct __SerdeDeserializeWithStruct $impl_generics $where_clause {
|
||||||
|
value: $field_ty,
|
||||||
|
phantom: ::std::marker::PhantomData<$phantom_ty>,
|
||||||
|
}
|
||||||
|
).unwrap(),
|
||||||
|
quote_stmt!(cx,
|
||||||
|
impl $impl_generics _serde::de::Deserialize for $wrapper_ty $where_clause {
|
||||||
|
fn deserialize<__D>(__d: &mut __D) -> ::std::result::Result<Self, __D::Error>
|
||||||
|
where __D: _serde::de::Deserializer
|
||||||
|
{
|
||||||
|
let value = try!($deserialize_with(__d));
|
||||||
|
Ok(__SerdeDeserializeWithStruct {
|
||||||
|
value: value,
|
||||||
|
phantom: ::std::marker::PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).unwrap(),
|
||||||
|
wrapper_ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expr_is_missing(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
attrs: &attr::FieldAttrs,
|
||||||
|
) -> P<ast::Expr> {
|
||||||
|
if let Some(expr) = attrs.default_expr_if_missing() {
|
||||||
|
return expr.clone();
|
||||||
|
}
|
||||||
|
let name = attrs.name().deserialize_name_expr();
|
||||||
|
match attrs.deserialize_with() {
|
||||||
|
None => {
|
||||||
|
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
quote_expr!(cx, return Err(
|
||||||
|
<__V::Error as _serde::de::Error>::missing_field($name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
|
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
|
||||||
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
|
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
|
||||||
|
#![cfg_attr(feature = "nightly-testing", allow(too_many_arguments))]
|
||||||
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
|
#![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))]
|
||||||
@@ -11,9 +12,11 @@ extern crate quasi;
|
|||||||
extern crate syntex;
|
extern crate syntex;
|
||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
#[cfg(feature = "with-syntex")]
|
||||||
|
#[macro_use]
|
||||||
extern crate syntex_syntax as syntax;
|
extern crate syntex_syntax as syntax;
|
||||||
|
|
||||||
#[cfg(not(feature = "with-syntex"))]
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
#[macro_use]
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
#[cfg(not(feature = "with-syntex"))]
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod attr;
|
mod attr;
|
||||||
|
mod bound;
|
||||||
mod de;
|
mod de;
|
||||||
mod error;
|
mod error;
|
||||||
mod ser;
|
mod ser;
|
||||||
|
|||||||
+79
-41
@@ -8,10 +8,10 @@ use syntax::ast::{
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ext::build::AstBuilder;
|
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use attr;
|
use attr;
|
||||||
|
use bound;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
pub fn expand_derive_serialize(
|
pub fn expand_derive_serialize(
|
||||||
@@ -60,11 +60,7 @@ fn serialize_item(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let impl_generics = builder.from_generics(generics.clone())
|
let impl_generics = build_impl_generics(cx, builder, item, generics);
|
||||||
.add_ty_param_bound(
|
|
||||||
builder.path().global().ids(&["serde", "ser", "Serialize"]).build()
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let ty = builder.ty().path()
|
let ty = builder.ty().path()
|
||||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||||
@@ -78,15 +74,57 @@ fn serialize_item(
|
|||||||
|
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
|
let dummy_const = builder.id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident));
|
||||||
|
|
||||||
Ok(quote_item!(cx,
|
Ok(quote_item!(cx,
|
||||||
impl $impl_generics ::serde::ser::Serialize for $ty $where_clause {
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
const $dummy_const: () = {
|
||||||
where __S: ::serde::ser::Serializer,
|
extern crate serde as _serde;
|
||||||
{
|
#[automatically_derived]
|
||||||
$body
|
impl $impl_generics _serde::ser::Serialize for $ty $where_clause {
|
||||||
|
fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
||||||
|
where __S: _serde::ser::Serializer,
|
||||||
|
{
|
||||||
|
$body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the generics in the input, plus a bound `T: Serialize` for each generic
|
||||||
|
// field type that will be serialized by us.
|
||||||
|
fn build_impl_generics(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
) -> ast::Generics {
|
||||||
|
let generics = bound::without_defaults(generics);
|
||||||
|
let generics = bound::with_bound(cx, builder, item, &generics,
|
||||||
|
&serialized_by_us,
|
||||||
|
&builder.path().ids(&["_serde", "ser", "Serialize"]).build());
|
||||||
|
generics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields with a `skip_serializing` or `serialize_with` attribute are not
|
||||||
|
// serialized by us. All other fields may need a `T: Serialize` bound where T is
|
||||||
|
// the type of the field.
|
||||||
|
fn serialized_by_us(field: &ast::StructField) -> bool {
|
||||||
|
for meta_items in field.attrs.iter().filter_map(attr::get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::NameValue(ref name, _) if name == &"serialize_with" => {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap())
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_body(
|
fn serialize_body(
|
||||||
@@ -151,7 +189,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.ident.is_some()) {
|
||||||
cx.span_bug(span, "tuple struct has named fields")
|
cx.span_bug(span, "tuple struct has named fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +203,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.ident.is_none()) {
|
||||||
cx.span_bug(span, "struct has unnamed fields")
|
cx.span_bug(span, "struct has unnamed fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +226,7 @@ fn serialize_unit_struct(
|
|||||||
let type_name = container_attrs.name().serialize_name_expr();
|
let type_name = container_attrs.name().serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx,
|
Ok(quote_expr!(cx,
|
||||||
serializer.serialize_unit_struct($type_name)
|
_serializer.serialize_unit_struct($type_name)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +237,7 @@ fn serialize_newtype_struct(
|
|||||||
let type_name = container_attrs.name().serialize_name_expr();
|
let type_name = container_attrs.name().serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx,
|
Ok(quote_expr!(cx,
|
||||||
serializer.serialize_newtype_struct($type_name, &self.0)
|
_serializer.serialize_newtype_struct($type_name, &self.0)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +267,7 @@ fn serialize_tuple_struct(
|
|||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.serialize_tuple_struct($type_name, Visitor {
|
_serializer.serialize_tuple_struct($type_name, Visitor {
|
||||||
value: self,
|
value: self,
|
||||||
state: 0,
|
state: 0,
|
||||||
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
||||||
@@ -264,7 +302,7 @@ fn serialize_struct(
|
|||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.serialize_struct($type_name, Visitor {
|
_serializer.serialize_struct($type_name, Visitor {
|
||||||
value: self,
|
value: self,
|
||||||
state: 0,
|
state: 0,
|
||||||
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
_structure_ty: ::std::marker::PhantomData::<&$ty>,
|
||||||
@@ -330,8 +368,8 @@ fn serialize_variant(
|
|||||||
|
|
||||||
Ok(quote_arm!(cx,
|
Ok(quote_arm!(cx,
|
||||||
$pat => {
|
$pat => {
|
||||||
::serde::ser::Serializer::serialize_unit_variant(
|
_serde::ser::Serializer::serialize_unit_variant(
|
||||||
serializer,
|
_serializer,
|
||||||
$type_name,
|
$type_name,
|
||||||
$variant_index,
|
$variant_index,
|
||||||
$variant_name,
|
$variant_name,
|
||||||
@@ -349,8 +387,8 @@ fn serialize_variant(
|
|||||||
|
|
||||||
Ok(quote_arm!(cx,
|
Ok(quote_arm!(cx,
|
||||||
$pat => {
|
$pat => {
|
||||||
::serde::ser::Serializer::serialize_newtype_variant(
|
_serde::ser::Serializer::serialize_newtype_variant(
|
||||||
serializer,
|
_serializer,
|
||||||
$type_name,
|
$type_name,
|
||||||
$variant_index,
|
$variant_index,
|
||||||
$variant_name,
|
$variant_name,
|
||||||
@@ -399,9 +437,9 @@ fn serialize_variant(
|
|||||||
field_names.iter()
|
field_names.iter()
|
||||||
.zip(fields.iter())
|
.zip(fields.iter())
|
||||||
.map(|(id, field)| {
|
.map(|(id, field)| {
|
||||||
let name = match field.node.kind {
|
let name = match field.ident {
|
||||||
ast::NamedField(name, _) => name,
|
Some(name) => name,
|
||||||
ast::UnnamedField(_) => {
|
None => {
|
||||||
cx.span_bug(field.span, "struct variant has unnamed fields")
|
cx.span_bug(field.span, "struct variant has unnamed fields")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -447,7 +485,7 @@ fn serialize_tuple_variant(
|
|||||||
builder.ty()
|
builder.ty()
|
||||||
.ref_()
|
.ref_()
|
||||||
.lifetime("'__a")
|
.lifetime("'__a")
|
||||||
.build_ty(field.node.ty.clone())
|
.build_ty(field.ty.clone())
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
@@ -473,7 +511,7 @@ fn serialize_tuple_variant(
|
|||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, Visitor {
|
_serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, Visitor {
|
||||||
value: $value_expr,
|
value: $value_expr,
|
||||||
state: 0,
|
state: 0,
|
||||||
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
||||||
@@ -502,12 +540,12 @@ fn serialize_struct_variant(
|
|||||||
.with_generics(variant_generics.clone())
|
.with_generics(variant_generics.clone())
|
||||||
.with_fields(
|
.with_fields(
|
||||||
fields.iter().map(|field| {
|
fields.iter().map(|field| {
|
||||||
builder.struct_field(field.node.ident().expect("struct has unnamed fields"))
|
builder.struct_field(field.ident.expect("struct has unnamed fields"))
|
||||||
.with_attrs(field.node.attrs.iter().cloned())
|
.with_attrs(field.attrs.iter().cloned())
|
||||||
.ty()
|
.ty()
|
||||||
.ref_()
|
.ref_()
|
||||||
.lifetime("'__serde_variant")
|
.lifetime("'__serde_variant")
|
||||||
.build_ty(field.node.ty.clone())
|
.build_ty(field.ty.clone())
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.field("__serde_container_ty")
|
.field("__serde_container_ty")
|
||||||
@@ -520,7 +558,7 @@ fn serialize_struct_variant(
|
|||||||
.zip(field_names.iter())
|
.zip(field_names.iter())
|
||||||
.map(|(field, field_name)| {
|
.map(|(field, field_name)| {
|
||||||
(
|
(
|
||||||
field.node.ident().expect("struct has unnamed fields"),
|
field.ident.expect("struct has unnamed fields"),
|
||||||
builder.expr().id(field_name),
|
builder.expr().id(field_name),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -557,7 +595,7 @@ fn serialize_struct_variant(
|
|||||||
$variant_struct
|
$variant_struct
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.serialize_struct_variant(
|
_serializer.serialize_struct_variant(
|
||||||
$container_name,
|
$container_name,
|
||||||
$variant_index,
|
$variant_index,
|
||||||
$variant_name,
|
$variant_name,
|
||||||
@@ -582,7 +620,7 @@ fn serialize_tuple_struct_visitor(
|
|||||||
let arms: Vec<ast::Arm> = (0 .. fields)
|
let arms: Vec<ast::Arm> = (0 .. fields)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let expr = builder.expr().method_call(serializer_method)
|
let expr = builder.expr().method_call(serializer_method)
|
||||||
.id("serializer")
|
.id("_serializer")
|
||||||
.arg().ref_().tup_field(i).field("value").self_()
|
.arg().ref_().tup_field(i).field("value").self_()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -616,12 +654,12 @@ fn serialize_tuple_struct_visitor(
|
|||||||
).unwrap(),
|
).unwrap(),
|
||||||
|
|
||||||
quote_item!(cx,
|
quote_item!(cx,
|
||||||
impl $visitor_impl_generics ::serde::ser::SeqVisitor
|
impl $visitor_impl_generics _serde::ser::SeqVisitor
|
||||||
for Visitor $visitor_generics
|
for Visitor $visitor_generics
|
||||||
$where_clause {
|
$where_clause {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
|
fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
|
||||||
where S: ::serde::ser::Serializer
|
where __S: _serde::ser::Serializer
|
||||||
{
|
{
|
||||||
match self.state {
|
match self.state {
|
||||||
$arms
|
$arms
|
||||||
@@ -656,7 +694,7 @@ fn serialize_struct_visitor(
|
|||||||
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field())
|
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (ref field, ref field_attr))| {
|
.map(|(i, (ref field, ref field_attr))| {
|
||||||
let name = field.node.ident().expect("struct has unnamed field");
|
let name = field.ident.expect("struct has unnamed field");
|
||||||
|
|
||||||
let key_expr = field_attr.name().serialize_name_expr();
|
let key_expr = field_attr.name().serialize_name_expr();
|
||||||
|
|
||||||
@@ -672,7 +710,7 @@ fn serialize_struct_visitor(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let expr = quote_expr!(cx,
|
let expr = quote_expr!(cx,
|
||||||
serializer.$serializer_method($key_expr, $field_expr)
|
_serializer.$serializer_method($key_expr, $field_expr)
|
||||||
);
|
);
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
@@ -721,12 +759,12 @@ fn serialize_struct_visitor(
|
|||||||
|
|
||||||
quote_item!(cx,
|
quote_item!(cx,
|
||||||
impl $visitor_impl_generics
|
impl $visitor_impl_generics
|
||||||
::serde::ser::MapVisitor
|
_serde::ser::MapVisitor
|
||||||
for Visitor $visitor_generics
|
for Visitor $visitor_generics
|
||||||
$where_clause {
|
$where_clause {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
|
fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
|
||||||
where S: ::serde::ser::Serializer,
|
where __S: _serde::ser::Serializer,
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
match self.state {
|
match self.state {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_macros"
|
name = "serde_macros"
|
||||||
version = "0.7.0"
|
version = "0.7.5"
|
||||||
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"
|
||||||
@@ -17,12 +17,12 @@ nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-tes
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clippy = { version = "^0.*", optional = true }
|
clippy = { version = "^0.*", optional = true }
|
||||||
serde_codegen = { version = "^0.7.0", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
serde_codegen = { version = "^0.7.5", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
compiletest_rs = "^0.0.11"
|
compiletest_rs = "^0.1.1"
|
||||||
rustc-serialize = "^0.3.16"
|
rustc-serialize = "^0.3.16"
|
||||||
serde = { version = "^0.7.0", path = "../serde" }
|
serde = { version = "^0.7.5", path = "../serde" }
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "test"
|
name = "test"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_tests"
|
name = "serde_tests"
|
||||||
version = "0.6.3"
|
version = "0.7.5"
|
||||||
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"
|
||||||
@@ -14,14 +14,14 @@ build = "build.rs"
|
|||||||
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
|
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
syntex = { version = "^0.29.0" }
|
syntex = { version = "^0.32.0" }
|
||||||
syntex_syntax = { version = "^0.29.0" }
|
syntex_syntax = { version = "^0.32.0" }
|
||||||
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
|
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-serialize = "^0.3.16"
|
rustc-serialize = "^0.3.16"
|
||||||
serde = { version = "*", path = "../serde" }
|
serde = { version = "*", path = "../serde" }
|
||||||
syntex = "^0.29.0"
|
syntex = "^0.32.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clippy = { version = "^0.*", optional = true }
|
clippy = { version = "^0.*", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#![cfg_attr(feature = "nightly", feature(plugin))]
|
#![cfg_attr(feature = "nightly", feature(plugin))]
|
||||||
#![cfg_attr(feature = "nightly", plugin(clippy))]
|
#![cfg_attr(feature = "nightly", plugin(clippy))]
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/test.rs"));
|
include!(concat!(env!("OUT_DIR"), "/test.rs"));
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ mod token;
|
|||||||
mod test_annotations;
|
mod test_annotations;
|
||||||
mod test_bytes;
|
mod test_bytes;
|
||||||
mod test_de;
|
mod test_de;
|
||||||
|
mod test_gen;
|
||||||
mod test_macros;
|
mod test_macros;
|
||||||
mod test_ser;
|
mod test_ser;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::default::Default;
|
extern crate serde;
|
||||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
|
|
||||||
use token::{
|
use token::{
|
||||||
Error,
|
Error,
|
||||||
@@ -10,23 +10,33 @@ use token::{
|
|||||||
assert_de_tokens_error
|
assert_de_tokens_error
|
||||||
};
|
};
|
||||||
|
|
||||||
trait Trait: Sized {
|
trait MyDefault: Sized {
|
||||||
fn my_default() -> Self;
|
fn my_default() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ShouldSkip: Sized {
|
||||||
fn should_skip(&self) -> bool;
|
fn should_skip(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SerializeWith: Sized {
|
||||||
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||||
where S: Serializer;
|
where S: Serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DeserializeWith: Sized {
|
||||||
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
||||||
where D: Deserializer;
|
where D: Deserializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trait for i32 {
|
impl MyDefault for i32 {
|
||||||
fn my_default() -> Self { 123 }
|
fn my_default() -> Self { 123 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShouldSkip for i32 {
|
||||||
fn should_skip(&self) -> bool { *self == 123 }
|
fn should_skip(&self) -> bool { *self == 123 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerializeWith for i32 {
|
||||||
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||||
where S: Serializer
|
where S: Serializer
|
||||||
{
|
{
|
||||||
@@ -36,7 +46,9 @@ impl Trait for i32 {
|
|||||||
false.serialize(ser)
|
false.serialize(ser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeserializeWith for i32 {
|
||||||
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
||||||
where D: Deserializer
|
where D: Deserializer
|
||||||
{
|
{
|
||||||
@@ -49,18 +61,25 @@ impl Trait for i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct DefaultStruct<A, B: Default, C> where C: Trait {
|
struct DefaultStruct<A, B, C, D, E>
|
||||||
|
where C: MyDefault,
|
||||||
|
E: MyDefault,
|
||||||
|
{
|
||||||
a1: A,
|
a1: A,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
a2: B,
|
a2: B,
|
||||||
#[serde(default="Trait::my_default")]
|
#[serde(default="MyDefault::my_default")]
|
||||||
a3: C,
|
a3: C,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
a4: D,
|
||||||
|
#[serde(skip_deserializing, default="MyDefault::my_default")]
|
||||||
|
a5: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_struct() {
|
fn test_default_struct() {
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DefaultStruct { a1: 1, a2: 2, a3: 3 },
|
&DefaultStruct { a1: 1, a2: 2, a3: 3, a4: 0, a5: 123 },
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("DefaultStruct", Some(3)),
|
Token::StructStart("DefaultStruct", Some(3)),
|
||||||
|
|
||||||
@@ -76,12 +95,20 @@ fn test_default_struct() {
|
|||||||
Token::Str("a3"),
|
Token::Str("a3"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a4"),
|
||||||
|
Token::I32(4),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a5"),
|
||||||
|
Token::I32(5),
|
||||||
|
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DefaultStruct { a1: 1, a2: 0, a3: 123 },
|
&DefaultStruct { a1: 1, a2: 0, a3: 123, a4: 0, a5: 123 },
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("DefaultStruct", Some(1)),
|
Token::StructStart("DefaultStruct", Some(1)),
|
||||||
|
|
||||||
@@ -95,22 +122,29 @@ fn test_default_struct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
enum DefaultEnum<A, B: Default, C> where C: Trait {
|
enum DefaultEnum<A, B, C, D, E>
|
||||||
|
where C: MyDefault,
|
||||||
|
E: MyDefault
|
||||||
|
{
|
||||||
Struct {
|
Struct {
|
||||||
a1: A,
|
a1: A,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
a2: B,
|
a2: B,
|
||||||
#[serde(default="Trait::my_default")]
|
#[serde(default="MyDefault::my_default")]
|
||||||
a3: C,
|
a3: C,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
a4: D,
|
||||||
|
#[serde(skip_deserializing, default="MyDefault::my_default")]
|
||||||
|
a5: E,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_enum() {
|
fn test_default_enum() {
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DefaultEnum::Struct { a1: 1, a2: 2, a3: 3 },
|
&DefaultEnum::Struct { a1: 1, a2: 2, a3: 3, a4: 0, a5: 123 },
|
||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("DefaultEnum", "Struct", Some(3)),
|
Token::EnumMapStart("DefaultEnum", "Struct", Some(5)),
|
||||||
|
|
||||||
Token::EnumMapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a1"),
|
Token::Str("a1"),
|
||||||
@@ -124,14 +158,22 @@ fn test_default_enum() {
|
|||||||
Token::Str("a3"),
|
Token::Str("a3"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a4"),
|
||||||
|
Token::I32(4),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a5"),
|
||||||
|
Token::I32(5),
|
||||||
|
|
||||||
Token::EnumMapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DefaultEnum::Struct { a1: 1, a2: 0, a3: 123 },
|
&DefaultEnum::Struct { a1: 1, a2: 0, a3: 123, a4: 0, a5: 123 },
|
||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("DefaultEnum", "Struct", Some(3)),
|
Token::EnumMapStart("DefaultEnum", "Struct", Some(5)),
|
||||||
|
|
||||||
Token::EnumMapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a1"),
|
Token::Str("a1"),
|
||||||
@@ -142,6 +184,108 @@ fn test_default_enum() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Does not implement std::default::Default.
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
struct NoStdDefault(i8);
|
||||||
|
|
||||||
|
impl MyDefault for NoStdDefault {
|
||||||
|
fn my_default() -> Self {
|
||||||
|
NoStdDefault(123)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
struct ContainsNoStdDefault<A: MyDefault> {
|
||||||
|
#[serde(default="MyDefault::my_default")]
|
||||||
|
a: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a struct field does not need to implement std::default::Default if
|
||||||
|
// it is annotated with `default=...`.
|
||||||
|
#[test]
|
||||||
|
fn test_no_std_default() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&ContainsNoStdDefault { a: NoStdDefault(123) },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("ContainsNoStdDefault", Some(1)),
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&ContainsNoStdDefault { a: NoStdDefault(8) },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("ContainsNoStdDefault", Some(1)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::StructNewType("NoStdDefault"),
|
||||||
|
Token::I8(8),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not implement Deserialize.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct NotDeserializeStruct(i8);
|
||||||
|
|
||||||
|
impl Default for NotDeserializeStruct {
|
||||||
|
fn default() -> Self {
|
||||||
|
NotDeserializeStruct(123)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeserializeWith for NotDeserializeStruct {
|
||||||
|
fn deserialize_with<D>(_: &mut D) -> Result<Self, D::Error>
|
||||||
|
where D: Deserializer
|
||||||
|
{
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not implement Deserialize.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum NotDeserializeEnum { Trouble }
|
||||||
|
|
||||||
|
impl MyDefault for NotDeserializeEnum {
|
||||||
|
fn my_default() -> Self {
|
||||||
|
NotDeserializeEnum::Trouble
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
a: A,
|
||||||
|
#[serde(skip_deserializing, default)]
|
||||||
|
b: B,
|
||||||
|
#[serde(deserialize_with="DeserializeWith::deserialize_with", default)]
|
||||||
|
c: C,
|
||||||
|
#[serde(skip_deserializing, default="MyDefault::my_default")]
|
||||||
|
e: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a struct field does not need to implement Deserialize if it is
|
||||||
|
// annotated with skip_deserializing, whether using the std Default or a
|
||||||
|
// custom default.
|
||||||
|
#[test]
|
||||||
|
fn test_elt_not_deserialize() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&ContainsNotDeserialize {
|
||||||
|
a: NotDeserializeStruct(123),
|
||||||
|
b: NotDeserializeStruct(123),
|
||||||
|
c: NotDeserializeStruct(123),
|
||||||
|
e: NotDeserializeEnum::Trouble,
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
Token::StructStart("ContainsNotDeserialize", Some(3)),
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct DenyUnknown {
|
struct DenyUnknown {
|
||||||
@@ -152,7 +296,7 @@ struct DenyUnknown {
|
|||||||
fn test_ignore_unknown() {
|
fn test_ignore_unknown() {
|
||||||
// 'Default' allows unknown. Basic smoke test of ignore...
|
// 'Default' allows unknown. Basic smoke test of ignore...
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DefaultStruct { a1: 1, a2: 2, a3: 3 },
|
&DefaultStruct { a1: 1, a2: 2, a3: 3, a4: 0, a5: 123 },
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("DefaultStruct", Some(5)),
|
Token::StructStart("DefaultStruct", Some(5)),
|
||||||
|
|
||||||
@@ -389,11 +533,11 @@ fn test_rename_enum() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
struct SkipSerializingStruct<'a, B, C> where C: Trait {
|
struct SkipSerializingStruct<'a, B, C> where C: ShouldSkip {
|
||||||
a: &'a i8,
|
a: &'a i8,
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
b: B,
|
b: B,
|
||||||
#[serde(skip_serializing_if="Trait::should_skip")]
|
#[serde(skip_serializing_if="ShouldSkip::should_skip")]
|
||||||
c: C,
|
c: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,12 +584,12 @@ fn test_skip_serializing_struct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
enum SkipSerializingEnum<'a, B, C> where C: Trait {
|
enum SkipSerializingEnum<'a, B, C> where C: ShouldSkip {
|
||||||
Struct {
|
Struct {
|
||||||
a: &'a i8,
|
a: &'a i8,
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
_b: B,
|
_b: B,
|
||||||
#[serde(skip_serializing_if="Trait::should_skip")]
|
#[serde(skip_serializing_if="ShouldSkip::should_skip")]
|
||||||
c: C,
|
c: C,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,10 +636,62 @@ fn test_skip_serializing_enum() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct NotSerializeStruct(i8);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum NotSerializeEnum { Trouble }
|
||||||
|
|
||||||
|
impl SerializeWith for NotSerializeEnum {
|
||||||
|
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
"trouble".serialize(ser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
struct SerializeWithStruct<'a, B> where B: Trait {
|
struct ContainsNotSerialize<'a, B, C, D> where B: 'a, D: SerializeWith {
|
||||||
|
a: &'a Option<i8>,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
b: &'a B,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
c: Option<C>,
|
||||||
|
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||||
|
d: D,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_elt_not_serialize() {
|
||||||
|
let a = 1;
|
||||||
|
assert_ser_tokens(
|
||||||
|
&ContainsNotSerialize {
|
||||||
|
a: &Some(a),
|
||||||
|
b: &NotSerializeStruct(2),
|
||||||
|
c: Some(NotSerializeEnum::Trouble),
|
||||||
|
d: NotSerializeEnum::Trouble,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::StructStart("ContainsNotSerialize", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::Option(true),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::Str("trouble"),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
struct SerializeWithStruct<'a, B> where B: SerializeWith {
|
||||||
a: &'a i8,
|
a: &'a i8,
|
||||||
#[serde(serialize_with="Trait::serialize_with")]
|
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||||
b: B,
|
b: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,10 +740,10 @@ fn test_serialize_with_struct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
enum SerializeWithEnum<'a, B> where B: Trait {
|
enum SerializeWithEnum<'a, B> where B: SerializeWith {
|
||||||
Struct {
|
Struct {
|
||||||
a: &'a i8,
|
a: &'a i8,
|
||||||
#[serde(serialize_with="Trait::serialize_with")]
|
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||||
b: B,
|
b: B,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,9 +793,9 @@ fn test_serialize_with_enum() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
struct DeserializeWithStruct<B> where B: Trait {
|
struct DeserializeWithStruct<B> where B: DeserializeWith {
|
||||||
a: i8,
|
a: i8,
|
||||||
#[serde(deserialize_with="Trait::deserialize_with")]
|
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
|
||||||
b: B,
|
b: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,10 +843,10 @@ fn test_deserialize_with_struct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
enum DeserializeWithEnum<B> where B: Trait {
|
enum DeserializeWithEnum<B> where B: DeserializeWith {
|
||||||
Struct {
|
Struct {
|
||||||
a: i8,
|
a: i8,
|
||||||
#[serde(deserialize_with="Trait::deserialize_with")]
|
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
|
||||||
b: B,
|
b: B,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,3 +893,57 @@ fn test_deserialize_with_enum() {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_renamed_field_struct() {
|
||||||
|
assert_de_tokens_error::<RenameStruct>(
|
||||||
|
vec![
|
||||||
|
Token::StructStart("Superhero", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
Error::MissingFieldError("a3"),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<RenameStructSerializeDeserialize>(
|
||||||
|
vec![
|
||||||
|
Token::StructStart("SuperheroDe", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
Error::MissingFieldError("a5"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_renamed_field_enum() {
|
||||||
|
assert_de_tokens_error::<RenameEnum>(
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("Superhero", "barry_allan", Some(1)),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
],
|
||||||
|
Error::MissingFieldError("b"),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<RenameEnumSerializeDeserialize<i8>>(
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(0),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
],
|
||||||
|
Error::MissingFieldError("d"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use serde;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::error;
|
use std::error;
|
||||||
use serde::Serialize;
|
|
||||||
use serde::bytes::{ByteBuf, Bytes};
|
extern crate serde;
|
||||||
|
use self::serde::Serialize;
|
||||||
|
use self::serde::bytes::{ByteBuf, Bytes};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
|||||||
use std::net;
|
use std::net;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::de::{Deserializer, Visitor};
|
extern crate serde;
|
||||||
|
use self::serde::de::Deserializer;
|
||||||
|
|
||||||
use token::{
|
use token::{
|
||||||
Error,
|
Error,
|
||||||
@@ -24,6 +25,7 @@ struct TupleStruct(i32, i32, i32);
|
|||||||
struct Struct {
|
struct Struct {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
c: i32,
|
c: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +62,17 @@ macro_rules! declare_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! declare_error_tests {
|
||||||
|
($($name:ident<$target:ident> { $tokens:expr, $expected:expr, })+) => {
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
assert_de_tokens_error::<$target>($tokens, $expected);
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
@@ -524,7 +537,40 @@ declare_tests! {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_struct {
|
test_struct {
|
||||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::MapStart(Some(3)),
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::StructStart("Struct", Some(3)),
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::SeqStart(Some(3)),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(2),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
test_struct_with_skip {
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
Token::MapStart(Some(3)),
|
Token::MapStart(Some(3)),
|
||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
@@ -537,9 +583,13 @@ declare_tests! {
|
|||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::I32(4),
|
||||||
Token::MapEnd,
|
Token::MapEnd,
|
||||||
],
|
],
|
||||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
Token::StructStart("Struct", Some(3)),
|
Token::StructStart("Struct", Some(3)),
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
@@ -552,6 +602,10 @@ declare_tests! {
|
|||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::I32(4),
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -611,6 +665,21 @@ declare_tests! {
|
|||||||
Token::Unit,
|
Token::Unit,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
test_box {
|
||||||
|
Box::new(0i32) => vec![Token::I32(0)],
|
||||||
|
}
|
||||||
|
test_boxed_slice {
|
||||||
|
Box::new([0, 1, 2]) => vec![
|
||||||
|
Token::SeqStart(Some(3)),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(0),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(1),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(2),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
}
|
||||||
test_net_ipv4addr {
|
test_net_ipv4addr {
|
||||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => vec![Token::Str("1.2.3.4")],
|
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => vec![Token::Str("1.2.3.4")],
|
||||||
}
|
}
|
||||||
@@ -638,12 +707,50 @@ fn test_net_ipaddr() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
declare_error_tests! {
|
||||||
fn test_enum_error() {
|
test_unknown_variant<Enum> {
|
||||||
assert_de_tokens_error::<Enum>(
|
|
||||||
vec![
|
vec![
|
||||||
Token::EnumUnit("Enum", "Foo"),
|
Token::EnumUnit("Enum", "Foo"),
|
||||||
],
|
],
|
||||||
Error::UnknownVariantError("Foo".to_owned()),
|
Error::UnknownVariantError("Foo".to_owned()),
|
||||||
)
|
}
|
||||||
|
test_struct_seq_too_long<Struct> {
|
||||||
|
vec![
|
||||||
|
Token::SeqStart(Some(4)),
|
||||||
|
Token::SeqSep, Token::I32(1),
|
||||||
|
Token::SeqSep, Token::I32(2),
|
||||||
|
Token::SeqSep, Token::I32(3),
|
||||||
|
Token::SeqSep, Token::I32(4),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
Error::UnexpectedToken(Token::SeqSep),
|
||||||
|
}
|
||||||
|
test_duplicate_field_struct<Struct> {
|
||||||
|
vec![
|
||||||
|
Token::MapStart(Some(3)),
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(3),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
Error::DuplicateFieldError("a"),
|
||||||
|
}
|
||||||
|
test_duplicate_field_enum<Enum> {
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("Enum", "Map", Some(3)),
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(3),
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
],
|
||||||
|
Error::DuplicateFieldError("a"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// These just test that serde_codegen is able to produce code that compiles
|
||||||
|
// successfully when there are a variety of generics involved.
|
||||||
|
|
||||||
|
extern crate serde;
|
||||||
|
use self::serde::ser::{Serialize, Serializer};
|
||||||
|
use self::serde::de::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct With<T> {
|
||||||
|
t: T,
|
||||||
|
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||||
|
i: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct WithRef<'a, T: 'a> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
t: Option<&'a T>,
|
||||||
|
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||||
|
i: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Bounds<T: Serialize + Deserialize> {
|
||||||
|
t: T,
|
||||||
|
option: Option<T>,
|
||||||
|
boxed: Box<T>,
|
||||||
|
option_boxed: Option<Box<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct NoBounds<T> {
|
||||||
|
t: T,
|
||||||
|
option: Option<T>,
|
||||||
|
boxed: Box<T>,
|
||||||
|
option_boxed: Option<Box<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
enum EnumWith<T> {
|
||||||
|
A(
|
||||||
|
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||||
|
i32),
|
||||||
|
B {
|
||||||
|
t: T,
|
||||||
|
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||||
|
i: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
fn ser_i32<S: Serializer>(_: &i32, _: &mut S) -> Result<(), S::Error> { panic!() }
|
||||||
|
|
||||||
|
fn de_i32<D: Deserializer>(_: &mut D) -> Result<i32, D::Error> { panic!() }
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
use token::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens};
|
use token::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6,6 +7,13 @@ trait Trait {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// That tests that the derived Serialize implementation doesn't trigger
|
||||||
|
// any warning about `serializer` not being used, in case of empty enums.
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[deny(unused_variables)]
|
||||||
|
enum Void {}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct NamedUnit;
|
struct NamedUnit;
|
||||||
|
|
||||||
@@ -136,6 +144,19 @@ pub enum GenericEnum<T, U> {
|
|||||||
Map { x: T, y: U },
|
Map { x: T, y: U },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait AssociatedType {
|
||||||
|
type X;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssociatedType for i32 {
|
||||||
|
type X = i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct DefaultTyParam<T: AssociatedType<X=i32> = i32> {
|
||||||
|
phantom: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_named_unit() {
|
fn test_named_unit() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
@@ -594,3 +615,19 @@ fn test_generic_enum_map() {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_ty_param() {
|
||||||
|
assert_tokens(
|
||||||
|
&DefaultTyParam::<i32> { phantom: PhantomData },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("DefaultTyParam", Some(1)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("phantom"),
|
||||||
|
Token::UnitStruct("PhantomData"),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -262,6 +262,21 @@ declare_ser_tests! {
|
|||||||
Token::EnumMapEnd,
|
Token::EnumMapEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
test_box {
|
||||||
|
Box::new(0i32) => &[Token::I32(0)],
|
||||||
|
}
|
||||||
|
test_boxed_slice {
|
||||||
|
Box::new([0, 1, 2]) => &[
|
||||||
|
Token::SeqArrayStart(3),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(0),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(1),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(2),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
}
|
||||||
test_net_ipv4addr {
|
test_net_ipv4addr {
|
||||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ use std::fmt;
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
use serde::ser::{self, Serialize};
|
extern crate serde;
|
||||||
use serde::de;
|
use self::serde::ser::{self, Serialize};
|
||||||
use serde::de::value::{self, ValueDeserializer};
|
use self::serde::de;
|
||||||
|
use self::serde::de::value::{self, ValueDeserializer};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Token<'a> {
|
pub enum Token<'a> {
|
||||||
@@ -409,6 +410,7 @@ pub enum Error {
|
|||||||
UnknownFieldError(String),
|
UnknownFieldError(String),
|
||||||
UnknownVariantError(String),
|
UnknownVariantError(String),
|
||||||
MissingFieldError(&'static str),
|
MissingFieldError(&'static str),
|
||||||
|
DuplicateFieldError(&'static str),
|
||||||
InvalidName(&'static str),
|
InvalidName(&'static str),
|
||||||
InvalidValue(String),
|
InvalidValue(String),
|
||||||
UnexpectedToken(Token<'static>),
|
UnexpectedToken(Token<'static>),
|
||||||
@@ -428,6 +430,10 @@ impl de::Error for Error {
|
|||||||
|
|
||||||
fn end_of_stream() -> Error { Error::EndOfStreamError }
|
fn end_of_stream() -> Error { Error::EndOfStreamError }
|
||||||
|
|
||||||
|
fn invalid_value(msg: &str) -> Error {
|
||||||
|
Error::InvalidValue(msg.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
fn unknown_field(field: &str) -> Error {
|
fn unknown_field(field: &str) -> Error {
|
||||||
Error::UnknownFieldError(field.to_owned())
|
Error::UnknownFieldError(field.to_owned())
|
||||||
}
|
}
|
||||||
@@ -439,6 +445,10 @@ impl de::Error for Error {
|
|||||||
fn missing_field(field: &'static str) -> Error {
|
fn missing_field(field: &'static str) -> Error {
|
||||||
Error::MissingFieldError(field)
|
Error::MissingFieldError(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn duplicate_field(field: &'static str) -> Error {
|
||||||
|
Error::DuplicateFieldError(field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
|||||||
Reference in New Issue
Block a user