mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 05:58:01 +00:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a09f05644 | |||
| 5923a0cd2f | |||
| 1576b5a8a0 | |||
| 2c4dbf5a84 | |||
| 021f4f2d70 | |||
| decc571988 | |||
| 322d7a90db | |||
| dd3f653103 | |||
| 46a1860601 | |||
| 84a573c926 | |||
| 7dfa8f43f4 | |||
| 7375b4e847 | |||
| 48da62ed07 | |||
| 9834af7ed9 | |||
| 6b404d8529 | |||
| 3119cc8857 | |||
| bb059b97c0 | |||
| b7188f7022 | |||
| a64fe99d1b | |||
| c716c4e261 | |||
| 3d2e3beafe | |||
| 1917e54a6e | |||
| 898b346d48 | |||
| e90adb20ef | |||
| a52e7f5554 | |||
| 7afb8b52ae | |||
| cb4694387e | |||
| 58fa302007 | |||
| bf33daf124 | |||
| 4b472be56e | |||
| bdffaf3ea1 | |||
| f197c3ce96 | |||
| 01dfad6705 | |||
| 2e06786262 | |||
| 578f34ecaf | |||
| 2c8767cb46 | |||
| 45c51d3198 | |||
| bd40830905 | |||
| 4e6cd2d63f | |||
| 2256a04926 | |||
| 660ea7bd7b | |||
| 7052833512 | |||
| 5c2cf5778f | |||
| b5c0406afe | |||
| 96cd910c92 | |||
| e0bd57d63c | |||
| 7c784f592e | |||
| 2c69ccdca4 | |||
| 66eddd4d9b | |||
| 1485f0a448 | |||
| 379c9e7148 | |||
| 6c2af4da7a | |||
| 2ff7d003ee | |||
| ea182e2561 | |||
| 938f42faf6 | |||
| cc115ca43a | |||
| f1b4072444 | |||
| 16d3e96b77 | |||
| 7d2423e856 | |||
| 9865ec23c7 | |||
| 76a321db5c | |||
| 004dcaec3b | |||
| 74eb2f52b8 | |||
| 9b7317fbb1 | |||
| ae806af644 |
+8
-1
@@ -3,7 +3,8 @@ rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- 1.5.0
|
||||
- 1.7.0
|
||||
- 1.8.0
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
@@ -18,10 +19,16 @@ script:
|
||||
- (cd serde && travis-cargo build)
|
||||
- (cd serde && travis-cargo test)
|
||||
- (cd serde && travis-cargo --only nightly test -- --features nightly-testing)
|
||||
- (cd serde && travis-cargo build -- --no-default-features)
|
||||
- (cd serde && travis-cargo --only nightly build -- --no-default-features)
|
||||
- (cd serde && travis-cargo --only nightly build -- --no-default-features --features alloc)
|
||||
- (cd serde && travis-cargo --only nightly build -- --no-default-features --features collections)
|
||||
- (cd serde_tests && travis-cargo test)
|
||||
- (cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing)
|
||||
- (cd serde_macros && travis-cargo --only nightly test -- --features nightly-testing)
|
||||
- (cd serde_macros && travis-cargo --only nightly bench -- --features nightly-testing)
|
||||
- (cd examples/serde-syntex-example && travis-cargo run)
|
||||
- (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --features nightly --no-default-features)
|
||||
- (cd serde && travis-cargo --only stable doc)
|
||||
- (cd serde_codegen && travis-cargo --only stable doc)
|
||||
- (cd serde_macros && travis-cargo --only nightly doc)
|
||||
|
||||
@@ -142,10 +142,7 @@ pub fn main() {
|
||||
let src = Path::new("src/main.rs.in");
|
||||
let dst = Path::new(&out_dir).join("main.rs");
|
||||
|
||||
let mut registry = syntex::Registry::new();
|
||||
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
serde_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -203,10 +200,7 @@ mod inner {
|
||||
let src = Path::new("src/main.rs.in");
|
||||
let dst = Path::new(&out_dir).join("main.rs");
|
||||
|
||||
let mut registry = syntex::Registry::new();
|
||||
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
serde_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,12 +682,15 @@ how types are serialized. Here are the supported annotations:
|
||||
|
||||
Container Annotations:
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[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(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. |
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[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(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(bound="T: MyTrait")]` | Where-clause for the Serialize and Deserialize impls. This replaces any bounds inferred by Serde. |
|
||||
| `#[serde(bound(serialize="T: MyTrait"))]` | Where-clause for the Serialize impl. |
|
||||
| `#[serde(bound(deserialize="T: MyTrait"))]` | Where-clause for the Deserialize impl. |
|
||||
|
||||
Variant Annotations:
|
||||
|
||||
@@ -705,18 +702,35 @@ Variant Annotations:
|
||||
|
||||
Field Annotations:
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[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(deserialize="name1"))]` | Deserialize this field with the given name |
|
||||
| `#[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(skip_serializing)]` | Do not serialize this value |
|
||||
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
|
||||
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
|
||||
| `#[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` |
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[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(deserialize="name1"))]` | Deserialize this field with the given name |
|
||||
| `#[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(skip_serializing)]` | Do not serialize this value |
|
||||
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
|
||||
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
|
||||
| `#[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` |
|
||||
| `#[serde(bound="T: MyTrait")]` | Where-clause for the Serialize and Deserialize impls. This replaces any bounds inferred by Serde for the current field. |
|
||||
| `#[serde(bound(serialize="T: MyTrait"))]` | Where-clause for the Serialize impl. |
|
||||
| `#[serde(bound(deserialize="T: MyTrait"))]` | Where-clause for the Deserialize impl. |
|
||||
|
||||
Using in `no_std` crates
|
||||
========================
|
||||
|
||||
The core `serde` package defines a number of features to enable usage in a
|
||||
variety of freestanding environments. Enable any or none of the following
|
||||
features, and use `default-features = false` in your `Cargo.toml`:
|
||||
|
||||
- `alloc` (implies `nightly`)
|
||||
- `collections` (implies `alloc` and `nightly`)
|
||||
- `std` (default)
|
||||
|
||||
If you only use `default-features = false`, you will receive a stock `no_std`
|
||||
serde with no support for any of the collection types.
|
||||
|
||||
Upgrading from Serde 0.6
|
||||
========================
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
paths = [
|
||||
"../serde",
|
||||
"../serde_codegen",
|
||||
"../serde_macros",
|
||||
]
|
||||
@@ -9,10 +9,10 @@ default = ["serde_codegen"]
|
||||
nightly = ["serde_macros"]
|
||||
|
||||
[build-dependencies]
|
||||
serde_codegen = { version = "^0.7.5", optional = true }
|
||||
syntex = "^0.32.0"
|
||||
serde_codegen = { version = "^0.7.10", optional = true }
|
||||
syntex = "^0.33.0"
|
||||
|
||||
[dependencies]
|
||||
serde = "^0.7.5"
|
||||
serde = "^0.7.10"
|
||||
serde_json = "^0.7.0"
|
||||
serde_macros = { version = "^0.7.5", optional = true }
|
||||
serde_macros = { version = "^0.7.10", optional = true }
|
||||
|
||||
@@ -2,12 +2,12 @@ This example demonstrates how to use Serde with Syntex. On stable or nightly
|
||||
with Syntex, it can be built with:
|
||||
|
||||
```
|
||||
% multirust run stable cargo run
|
||||
% rustup run stable cargo run
|
||||
Running `target/debug/serde-syntex-example`
|
||||
{"x":1,"y":2}
|
||||
Point { x: 1, y: 2 }
|
||||
|
||||
% multirust run nightly cargo run
|
||||
% rustup run nightly cargo run
|
||||
Running `target/debug/serde-syntex-example`
|
||||
{"x":1,"y":2}
|
||||
Point { x: 1, y: 2 }
|
||||
@@ -16,5 +16,5 @@ Point { x: 1, y: 2 }
|
||||
On nightly, it can use a plugin with:
|
||||
|
||||
```
|
||||
% multirust run nightly cargo run --features nightly --no-default-features
|
||||
% rustup run nightly cargo run --features nightly --no-default-features
|
||||
```
|
||||
|
||||
@@ -12,10 +12,7 @@ mod inner {
|
||||
let src = Path::new("src/main.rs.in");
|
||||
let dst = Path::new(&out_dir).join("main.rs");
|
||||
|
||||
let mut registry = syntex::Registry::new();
|
||||
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
serde_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![cfg_attr(nightly, feature(custom_derive, plugin))]
|
||||
#![cfg_attr(nightly, plugin(serde_macros))]
|
||||
#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
|
||||
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.7.5"
|
||||
version = "0.7.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -8,10 +8,16 @@ repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://serde-rs.github.io/serde/serde/"
|
||||
readme = "../README.md"
|
||||
keywords = ["serde", "serialization"]
|
||||
include = ["Cargo.toml", "src/**/*.rs"]
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
std = []
|
||||
nightly = []
|
||||
nightly-testing = ["clippy", "nightly"]
|
||||
alloc = ["nightly"]
|
||||
collections = ["alloc"]
|
||||
nightly-testing = ["clippy", "nightly", "std"]
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
|
||||
+159
-135
@@ -1,11 +1,15 @@
|
||||
//! Helper module to enable serializing bytes more efficiently
|
||||
|
||||
use std::ops;
|
||||
use std::fmt;
|
||||
use std::ascii;
|
||||
use core::{ops, fmt, char, iter, slice};
|
||||
use core::fmt::Write;
|
||||
|
||||
use ser;
|
||||
use de;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub use self::bytebuf::{ByteBuf, ByteBufVisitor};
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::Vec;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -17,7 +21,11 @@ pub struct Bytes<'a> {
|
||||
|
||||
impl<'a> fmt::Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "b\"{}\"", escape_bytestring(self.bytes))
|
||||
try!(f.write_str("b\""));
|
||||
for c in escape_bytestring(self.bytes) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +37,11 @@ impl<'a> From<&'a [u8]> for Bytes<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
|
||||
fn from(bytes: &'a Vec<u8>) -> Self {
|
||||
Bytes {
|
||||
bytes: &bytes,
|
||||
bytes: bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,157 +69,172 @@ impl<'a> ser::Serialize for Bytes<'a> {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
mod bytebuf {
|
||||
use core::ops;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::new(),
|
||||
use ser;
|
||||
use de;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::Vec;
|
||||
|
||||
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::with_capacity(cap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::with_capacity(cap)
|
||||
impl fmt::Debug for ByteBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str("b\""));
|
||||
for c in super::escape_bytestring(self.bytes.as_ref()) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ByteBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "b\"{}\"", escape_bytestring(self.bytes.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for ByteBuf {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ByteBuf {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
ByteBuf {
|
||||
bytes: bytes,
|
||||
impl Into<Vec<u8>> for ByteBuf {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Vec<u8>> for ByteBuf {
|
||||
fn as_ref(&self) -> &Vec<u8> {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ByteBuf {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Vec<u8>> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ByteBuf {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] { &self.bytes[..] }
|
||||
}
|
||||
|
||||
impl ops::DerefMut for ByteBuf {
|
||||
fn deref_mut(&mut self) -> &mut [u8] { &mut self.bytes[..] }
|
||||
}
|
||||
|
||||
impl ser::Serialize for ByteBuf {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(&self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This type implements the `serde::de::Visitor` trait for a `ByteBuf`.
|
||||
pub struct ByteBufVisitor;
|
||||
|
||||
impl de::Visitor for ByteBufVisitor {
|
||||
type Value = ByteBuf;
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(&mut self) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(ByteBuf {
|
||||
bytes: Vec::new(),
|
||||
})
|
||||
impl From<Vec<u8>> for ByteBuf {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
ByteBuf {
|
||||
bytes: bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<ByteBuf, V::Error>
|
||||
where V: de::SeqVisitor,
|
||||
{
|
||||
let (len, _) = visitor.size_hint();
|
||||
let mut values = Vec::with_capacity(len);
|
||||
impl AsRef<Vec<u8>> for ByteBuf {
|
||||
fn as_ref(&self) -> &Vec<u8> {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(value) = try!(visitor.visit()) {
|
||||
values.push(value);
|
||||
impl AsRef<[u8]> for ByteBuf {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Vec<u8>> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ByteBuf {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] { &self.bytes[..] }
|
||||
}
|
||||
|
||||
impl ops::DerefMut for ByteBuf {
|
||||
fn deref_mut(&mut self) -> &mut [u8] { &mut self.bytes[..] }
|
||||
}
|
||||
|
||||
impl ser::Serialize for ByteBuf {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This type implements the `serde::de::Visitor` trait for a `ByteBuf`.
|
||||
pub struct ByteBufVisitor;
|
||||
|
||||
impl de::Visitor for ByteBufVisitor {
|
||||
type Value = ByteBuf;
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(&mut self) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(ByteBuf {
|
||||
bytes: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
try!(visitor.end());
|
||||
#[inline]
|
||||
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<ByteBuf, V::Error>
|
||||
where V: de::SeqVisitor,
|
||||
{
|
||||
let (len, _) = visitor.size_hint();
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
Ok(ByteBuf {
|
||||
bytes: values,
|
||||
})
|
||||
while let Some(value) = try!(visitor.visit()) {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
try!(visitor.end());
|
||||
|
||||
Ok(ByteBuf {
|
||||
bytes: values,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
self.visit_byte_buf(v.to_vec())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(ByteBuf {
|
||||
bytes: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
self.visit_byte_buf(v.to_vec())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<ByteBuf, E>
|
||||
where E: de::Error,
|
||||
{
|
||||
Ok(ByteBuf {
|
||||
bytes: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Deserialize for ByteBuf {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<ByteBuf, D::Error>
|
||||
where D: de::Deserializer
|
||||
{
|
||||
deserializer.deserialize_bytes(ByteBufVisitor)
|
||||
impl de::Deserialize for ByteBuf {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<ByteBuf, D::Error>
|
||||
where D: de::Deserializer
|
||||
{
|
||||
deserializer.deserialize_bytes(ByteBufVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn escape_bytestring(bytes: &[u8]) -> String {
|
||||
let mut result = String::new();
|
||||
for &b in bytes {
|
||||
for esc in ascii::escape_default(b) {
|
||||
result.push(esc as char);
|
||||
}
|
||||
#[inline]
|
||||
fn escape_bytestring<'a>(bytes: &'a [u8]) -> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
|
||||
fn f(b: &u8) -> char::EscapeDefault {
|
||||
char::from_u32(*b as u32).unwrap().escape_default()
|
||||
}
|
||||
result
|
||||
bytes.iter().flat_map(f as fn(&u8) -> char::EscapeDefault)
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
// Rust 1.5 is unhappy that this private module is undocumented.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::{usize, u8, u16, u32, u64};
|
||||
use std::{isize, i8, i16, i32, i64};
|
||||
use std::{f32, f64};
|
||||
use std::mem::size_of;
|
||||
use core::{usize, u8, u16, u32, u64};
|
||||
use core::{isize, i8, i16, i32, i64};
|
||||
use core::{f32, f64};
|
||||
use core::mem::size_of;
|
||||
|
||||
/// Numbers which have upper and lower bounds
|
||||
pub trait Bounded {
|
||||
@@ -274,7 +274,7 @@ macro_rules! impl_to_primitive_float_to_float {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let n = $slf as f64;
|
||||
let max_value: $SrcT = ::std::$SrcT::MAX;
|
||||
let max_value: $SrcT = ::core::$SrcT::MAX;
|
||||
if -max_value as f64 <= n && n <= max_value as f64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
|
||||
+125
-64
@@ -1,30 +1,63 @@
|
||||
//! This module contains `Deserialize` and `Visitor` implementations.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{
|
||||
#[cfg(all(feature = "nightly", feature = "collections", not(feature = "std")))]
|
||||
use collections::borrow::Cow;
|
||||
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::{
|
||||
BinaryHeap,
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
LinkedList,
|
||||
VecDeque,
|
||||
Vec,
|
||||
String,
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::{
|
||||
HashMap,
|
||||
HashSet,
|
||||
BinaryHeap,
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
LinkedList,
|
||||
VecDeque,
|
||||
};
|
||||
#[cfg(feature = "nightly")]
|
||||
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
use collections::enum_set::{CLike, EnumSet};
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
use collections::borrow::ToOwned;
|
||||
|
||||
use core::hash::{Hash, BuildHasher};
|
||||
use core::marker::PhantomData;
|
||||
#[cfg(feature = "std")]
|
||||
use std::net;
|
||||
#[cfg(feature = "std")]
|
||||
use std::path;
|
||||
use core::str;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
#[cfg(all(feature = "nightly", feature = "alloc", not(feature = "std")))]
|
||||
use alloc::rc::Rc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(all(feature = "nightly", feature = "alloc", not(feature = "std")))]
|
||||
use alloc::arc::Arc;
|
||||
|
||||
#[cfg(all(feature = "nightly", feature = "alloc", not(feature = "std")))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use core::nonzero::{NonZero, Zeroable};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::num::Zero;
|
||||
use core::num::Zero;
|
||||
|
||||
use de::{
|
||||
Deserialize,
|
||||
@@ -85,7 +118,7 @@ impl Visitor for BoolVisitor {
|
||||
fn visit_str<E>(&mut self, s: &str) -> Result<bool, E>
|
||||
where E: Error,
|
||||
{
|
||||
match s.trim() {
|
||||
match s.trim_matches(::utils::Pattern_White_Space) {
|
||||
"true" => Ok(true),
|
||||
"false" => Ok(false),
|
||||
_ => Err(Error::invalid_type(Type::Bool)),
|
||||
@@ -151,10 +184,10 @@ impl<T> Visitor for PrimitiveVisitor<T>
|
||||
impl_deserialize_num_method!(f64, visit_f64, from_f64, Type::F64);
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
|
||||
fn visit_str<E>(&mut self, s: &str) -> Result<T, E>
|
||||
where E: Error,
|
||||
{
|
||||
str::FromStr::from_str(v.trim()).or_else(|_| {
|
||||
str::FromStr::from_str(s.trim_matches(::utils::Pattern_White_Space)).or_else(|_| {
|
||||
Err(Error::invalid_type(Type::Str))
|
||||
})
|
||||
}
|
||||
@@ -228,8 +261,10 @@ impl Deserialize for char {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
struct StringVisitor;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl Visitor for StringVisitor {
|
||||
type Value = String;
|
||||
|
||||
@@ -264,6 +299,7 @@ impl Visitor for StringVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl Deserialize for String {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<String, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -345,29 +381,30 @@ impl<T> Deserialize for PhantomData<T> where T: Deserialize {
|
||||
macro_rules! seq_impl {
|
||||
(
|
||||
$ty:ty,
|
||||
< $($constraints:ident),* >,
|
||||
$visitor_name:ident,
|
||||
$visitor_ty:ident < $($typaram:ident : $bound1:ident $(+ $bound2:ident)*),* >,
|
||||
$visitor:ident,
|
||||
$ctor:expr,
|
||||
$with_capacity:expr,
|
||||
$insert:expr
|
||||
) => {
|
||||
/// A visitor that produces a sequence.
|
||||
pub struct $visitor_name<T> {
|
||||
marker: PhantomData<T>,
|
||||
pub struct $visitor_ty<$($typaram),*> {
|
||||
marker: PhantomData<$ty>,
|
||||
}
|
||||
|
||||
impl<T> $visitor_name<T> {
|
||||
impl<$($typaram),*> $visitor_ty<$($typaram),*>
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
/// Construct a new sequence visitor.
|
||||
pub fn new() -> Self {
|
||||
$visitor_name {
|
||||
$visitor_ty {
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Visitor for $visitor_name<T>
|
||||
where T: $($constraints +)*,
|
||||
impl<$($typaram),*> Visitor for $visitor_ty<$($typaram),*>
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
type Value = $ty;
|
||||
|
||||
@@ -394,77 +431,77 @@ macro_rules! seq_impl {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deserialize for $ty
|
||||
where T: $($constraints +)*,
|
||||
impl<$($typaram),*> Deserialize for $ty
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<$ty, D::Error>
|
||||
where D: Deserializer,
|
||||
{
|
||||
deserializer.deserialize_seq($visitor_name::new())
|
||||
deserializer.deserialize_seq($visitor_ty::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
seq_impl!(
|
||||
BinaryHeap<T>,
|
||||
<Deserialize, Ord>,
|
||||
BinaryHeapVisitor,
|
||||
BinaryHeapVisitor<T: Deserialize + Ord>,
|
||||
visitor,
|
||||
BinaryHeap::new(),
|
||||
BinaryHeap::with_capacity(visitor.size_hint().0),
|
||||
BinaryHeap::push);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
seq_impl!(
|
||||
BTreeSet<T>,
|
||||
<Deserialize, Eq, Ord>,
|
||||
BTreeSetVisitor,
|
||||
BTreeSetVisitor<T: Deserialize + Eq + Ord>,
|
||||
visitor,
|
||||
BTreeSet::new(),
|
||||
BTreeSet::new(),
|
||||
BTreeSet::insert);
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
seq_impl!(
|
||||
EnumSet<T>,
|
||||
<Deserialize, CLike>,
|
||||
EnumSetVisitor,
|
||||
EnumSetVisitor<T: Deserialize + CLike>,
|
||||
visitor,
|
||||
EnumSet::new(),
|
||||
EnumSet::new(),
|
||||
EnumSet::insert);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
seq_impl!(
|
||||
LinkedList<T>,
|
||||
<Deserialize>,
|
||||
LinkedListVisitor,
|
||||
LinkedListVisitor<T: Deserialize>,
|
||||
visitor,
|
||||
LinkedList::new(),
|
||||
LinkedList::new(),
|
||||
LinkedList::push_back);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
seq_impl!(
|
||||
HashSet<T>,
|
||||
<Deserialize, Eq, Hash>,
|
||||
HashSetVisitor,
|
||||
HashSet<T, S>,
|
||||
HashSetVisitor<T: Deserialize + Eq + Hash,
|
||||
S: BuildHasher + Default>,
|
||||
visitor,
|
||||
HashSet::new(),
|
||||
HashSet::with_capacity(visitor.size_hint().0),
|
||||
HashSet::with_hasher(S::default()),
|
||||
HashSet::with_capacity_and_hasher(visitor.size_hint().0, S::default()),
|
||||
HashSet::insert);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
seq_impl!(
|
||||
Vec<T>,
|
||||
<Deserialize>,
|
||||
VecVisitor,
|
||||
VecVisitor<T: Deserialize>,
|
||||
visitor,
|
||||
Vec::new(),
|
||||
Vec::with_capacity(visitor.size_hint().0),
|
||||
Vec::push);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
seq_impl!(
|
||||
VecDeque<T>,
|
||||
<Deserialize>,
|
||||
VecDequeVisitor,
|
||||
VecDequeVisitor<T: Deserialize>,
|
||||
visitor,
|
||||
VecDeque::new(),
|
||||
VecDeque::with_capacity(visitor.size_hint().0),
|
||||
@@ -684,30 +721,29 @@ tuple_impls! {
|
||||
macro_rules! map_impl {
|
||||
(
|
||||
$ty:ty,
|
||||
< $($constraints:ident),* >,
|
||||
$visitor_name:ident,
|
||||
$visitor_ty:ident < $($typaram:ident : $bound1:ident $(+ $bound2:ident)*),* >,
|
||||
$visitor:ident,
|
||||
$ctor:expr,
|
||||
$with_capacity:expr,
|
||||
$insert:expr
|
||||
$with_capacity:expr
|
||||
) => {
|
||||
/// A visitor that produces a map.
|
||||
pub struct $visitor_name<K, V> {
|
||||
pub struct $visitor_ty<$($typaram),*> {
|
||||
marker: PhantomData<$ty>,
|
||||
}
|
||||
|
||||
impl<K, V> $visitor_name<K, V> {
|
||||
impl<$($typaram),*> $visitor_ty<$($typaram),*>
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
/// Construct a `MapVisitor*<T>`.
|
||||
pub fn new() -> Self {
|
||||
$visitor_name {
|
||||
$visitor_ty {
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Visitor for $visitor_name<K, V>
|
||||
where K: $($constraints +)*,
|
||||
V: Deserialize,
|
||||
impl<$($typaram),*> Visitor for $visitor_ty<$($typaram),*>
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
type Value = $ty;
|
||||
|
||||
@@ -725,7 +761,7 @@ macro_rules! map_impl {
|
||||
let mut values = $with_capacity;
|
||||
|
||||
while let Some((key, value)) = try!($visitor.visit()) {
|
||||
$insert(&mut values, key, value);
|
||||
values.insert(key, value);
|
||||
}
|
||||
|
||||
try!($visitor.end());
|
||||
@@ -734,40 +770,40 @@ macro_rules! map_impl {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Deserialize for $ty
|
||||
where K: $($constraints +)*,
|
||||
V: Deserialize,
|
||||
impl<$($typaram),*> Deserialize for $ty
|
||||
where $($typaram: $bound1 $(+ $bound2)*),*
|
||||
{
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<$ty, D::Error>
|
||||
where D: Deserializer,
|
||||
{
|
||||
deserializer.deserialize_map($visitor_name::new())
|
||||
deserializer.deserialize_map($visitor_ty::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
map_impl!(
|
||||
BTreeMap<K, V>,
|
||||
<Deserialize, Eq, Ord>,
|
||||
BTreeMapVisitor,
|
||||
BTreeMapVisitor<K: Deserialize + Eq + Ord,
|
||||
V: Deserialize>,
|
||||
visitor,
|
||||
BTreeMap::new(),
|
||||
BTreeMap::new(),
|
||||
BTreeMap::insert);
|
||||
BTreeMap::new());
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
map_impl!(
|
||||
HashMap<K, V>,
|
||||
<Deserialize, Eq, Hash>,
|
||||
HashMapVisitor,
|
||||
HashMap<K, V, S>,
|
||||
HashMapVisitor<K: Deserialize + Eq + Hash,
|
||||
V: Deserialize,
|
||||
S: BuildHasher + Default>,
|
||||
visitor,
|
||||
HashMap::new(),
|
||||
HashMap::with_capacity(visitor.size_hint().0),
|
||||
HashMap::insert);
|
||||
HashMap::with_hasher(S::default()),
|
||||
HashMap::with_capacity_and_hasher(visitor.size_hint().0, S::default()));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "nightly", feature = "std"))]
|
||||
impl Deserialize for net::IpAddr {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -780,6 +816,7 @@ impl Deserialize for net::IpAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for net::Ipv4Addr {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -792,6 +829,7 @@ impl Deserialize for net::Ipv4Addr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for net::Ipv6Addr {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -806,6 +844,7 @@ impl Deserialize for net::Ipv6Addr {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for net::SocketAddr {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -818,6 +857,7 @@ impl Deserialize for net::SocketAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for net::SocketAddrV4 {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -830,6 +870,7 @@ impl Deserialize for net::SocketAddrV4 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for net::SocketAddrV6 {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -844,8 +885,10 @@ impl Deserialize for net::SocketAddrV6 {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
struct PathBufVisitor;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Visitor for PathBufVisitor {
|
||||
type Value = path::PathBuf;
|
||||
|
||||
@@ -862,6 +905,7 @@ impl Visitor for PathBufVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deserialize for path::PathBuf {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -872,6 +916,7 @@ impl Deserialize for path::PathBuf {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T: Deserialize> Deserialize for Box<T> {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Box<T>, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -881,6 +926,7 @@ impl<T: Deserialize> Deserialize for Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T: Deserialize> Deserialize for Box<[T]> {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Box<[T]>, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -890,6 +936,7 @@ impl<T: Deserialize> Deserialize for Box<[T]> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T: Deserialize> Deserialize for Arc<T> {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Arc<T>, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -899,6 +946,7 @@ impl<T: Deserialize> Deserialize for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T: Deserialize> Deserialize for Rc<T> {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Rc<T>, D::Error>
|
||||
where D: Deserializer,
|
||||
@@ -908,6 +956,7 @@ impl<T: Deserialize> Deserialize for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a, T: ?Sized> Deserialize for Cow<'a, T> where T: ToOwned, T::Owned: Deserialize, {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Cow<'a, T>, D::Error>
|
||||
@@ -954,7 +1003,10 @@ impl<T, E> Deserialize for Result<T, E> where T: Deserialize, E: Deserialize {
|
||||
impl ::de::Visitor for FieldVisitor {
|
||||
type Value = Field;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E> where E: Error {
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::string::ToString;
|
||||
match value {
|
||||
0 => Ok(Field::Ok),
|
||||
1 => Ok(Field::Err),
|
||||
@@ -962,6 +1014,15 @@ impl<T, E> Deserialize for Result<T, E> where T: Deserialize, E: Deserialize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E> where E: Error {
|
||||
match value {
|
||||
0 => Ok(Field::Ok),
|
||||
1 => Ok(Field::Err),
|
||||
_ => Err(Error::unknown_field("some number")),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: Error {
|
||||
match value {
|
||||
"Ok" => Ok(Field::Ok),
|
||||
|
||||
+17
-3
@@ -1,6 +1,12 @@
|
||||
//! Generic deserialization framework.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use error;
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "collections"))]
|
||||
use collections::{String, Vec};
|
||||
|
||||
pub mod impls;
|
||||
pub mod value;
|
||||
@@ -12,8 +18,13 @@ mod from_primitive;
|
||||
/// `Deserializer` error.
|
||||
pub trait Error: Sized + error::Error {
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn custom<T: Into<String>>(msg: T) -> Self;
|
||||
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn custom<T: Into<&'static str>>(msg: T) -> Self;
|
||||
|
||||
/// Raised when a `Deserialize` type unexpectedly hit the end of the stream.
|
||||
fn end_of_stream() -> Self;
|
||||
|
||||
@@ -28,6 +39,9 @@ pub trait Error: Sized + error::Error {
|
||||
}
|
||||
|
||||
/// Raised when a fixed sized sequence or map was passed in the wrong amount of arguments.
|
||||
///
|
||||
/// The parameter `len` is the number of arguments found in the serialization. The sequence
|
||||
/// may either expect more arguments or less arguments.
|
||||
fn invalid_length(len: usize) -> Self {
|
||||
Error::custom(format!("Invalid length: {}", len))
|
||||
}
|
||||
@@ -564,9 +578,7 @@ pub trait Visitor {
|
||||
fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
// FIXME: this allocation is required in order to be compatible with stable rust, which
|
||||
// doesn't support encoding a `char` into a stack buffer.
|
||||
self.visit_string(v.to_string())
|
||||
self.visit_str(::utils::encode_utf8(v).as_str())
|
||||
}
|
||||
|
||||
/// `visit_str` deserializes a `&str` into a `Value`.
|
||||
@@ -580,6 +592,7 @@ pub trait Visitor {
|
||||
/// a copy if it is deserializing a string from a `String` type. By default it passes a `&str`
|
||||
/// to the `visit_str` method.
|
||||
#[inline]
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
@@ -644,6 +657,7 @@ pub trait Visitor {
|
||||
}
|
||||
|
||||
/// `visit_byte_buf` deserializes a `Vec<u8>` into a `Value`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
|
||||
+72
-4
@@ -1,5 +1,6 @@
|
||||
//! This module supports deserializing from primitives with the `ValueDeserializer` trait.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::{
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
@@ -10,11 +11,31 @@ use std::collections::{
|
||||
hash_map,
|
||||
hash_set,
|
||||
};
|
||||
use std::hash::Hash;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "std")]
|
||||
use std::vec;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::{
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
Vec,
|
||||
String,
|
||||
btree_map,
|
||||
btree_set,
|
||||
vec,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
use collections::borrow::ToOwned;
|
||||
|
||||
use core::hash::Hash;
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use error;
|
||||
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use de;
|
||||
use bytes;
|
||||
@@ -25,7 +46,11 @@ use bytes;
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
/// The value had some custom error.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
Custom(String),
|
||||
/// The value had some custom error.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
Custom(&'static str),
|
||||
|
||||
/// The value had an incorrect type.
|
||||
InvalidType(de::Type),
|
||||
@@ -34,29 +59,60 @@ pub enum Error {
|
||||
InvalidLength(usize),
|
||||
|
||||
/// The value is invalid and cannot be deserialized.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
InvalidValue(String),
|
||||
/// The value is invalid and cannot be deserialized.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
InvalidValue(&'static str),
|
||||
|
||||
/// EOF while deserializing a value.
|
||||
EndOfStream,
|
||||
|
||||
/// Unknown variant in enum.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
UnknownVariant(String),
|
||||
/// Unknown variant in enum.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
UnknownVariant(&'static str),
|
||||
|
||||
/// Unknown field in struct.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
UnknownField(String),
|
||||
/// Unknown field in struct.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
UnknownField(&'static str),
|
||||
|
||||
/// Struct is missing a field.
|
||||
MissingField(&'static str),
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn custom<T: Into<String>>(msg: T) -> Self { Error::Custom(msg.into()) }
|
||||
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn custom<T: Into<&'static str>>(msg: T) -> Self { Error::Custom(msg.into()) }
|
||||
|
||||
fn end_of_stream() -> Self { Error::EndOfStream }
|
||||
fn invalid_type(ty: de::Type) -> Self { Error::InvalidType(ty) }
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn invalid_value(msg: &str) -> Self { Error::InvalidValue(msg.to_owned()) }
|
||||
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn invalid_value(msg: &str) -> Self { Error::InvalidValue("invalid value") }
|
||||
|
||||
fn invalid_length(len: usize) -> Self { Error::InvalidLength(len) }
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn unknown_variant(variant: &str) -> Self { Error::UnknownVariant(String::from(variant)) }
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn unknown_field(field: &str) -> Self { Error::UnknownField(String::from(field)) }
|
||||
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn unknown_variant(variant: &str) -> Self { Error::UnknownVariant("unknown variant") }
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn unknown_field(field: &str) -> Self { Error::UnknownField("unknown field") }
|
||||
fn missing_field(field: &'static str) -> Self { Error::MissingField(field) }
|
||||
}
|
||||
|
||||
@@ -238,8 +294,10 @@ impl<'a, E> de::VariantVisitor for StrDeserializer<'a, E>
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A helper deserializer that deserializes a `String`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub struct StringDeserializer<E>(Option<String>, PhantomData<E>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<E> ValueDeserializer<E> for String
|
||||
where E: de::Error,
|
||||
{
|
||||
@@ -250,6 +308,7 @@ impl<E> ValueDeserializer<E> for String
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<E> de::Deserializer for StringDeserializer<E>
|
||||
where E: de::Error,
|
||||
{
|
||||
@@ -274,6 +333,7 @@ impl<E> de::Deserializer for StringDeserializer<E>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a, E> de::VariantVisitor for StringDeserializer<E>
|
||||
where E: de::Error,
|
||||
{
|
||||
@@ -361,6 +421,7 @@ impl<I, T, E> de::SeqVisitor for SeqDeserializer<I, E>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T, E> ValueDeserializer<E> for Vec<T>
|
||||
where T: ValueDeserializer<E>,
|
||||
E: de::Error,
|
||||
@@ -373,6 +434,7 @@ impl<T, E> ValueDeserializer<E> for Vec<T>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T, E> ValueDeserializer<E> for BTreeSet<T>
|
||||
where T: ValueDeserializer<E> + Eq + Ord,
|
||||
E: de::Error,
|
||||
@@ -385,6 +447,7 @@ impl<T, E> ValueDeserializer<E> for BTreeSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T, E> ValueDeserializer<E> for HashSet<T>
|
||||
where T: ValueDeserializer<E> + Eq + Hash,
|
||||
E: de::Error,
|
||||
@@ -527,6 +590,7 @@ impl<I, K, V, E> de::MapVisitor for MapDeserializer<I, K, V, E>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<K, V, E> ValueDeserializer<E> for BTreeMap<K, V>
|
||||
where K: ValueDeserializer<E> + Eq + Ord,
|
||||
V: ValueDeserializer<E>,
|
||||
@@ -540,6 +604,7 @@ impl<K, V, E> ValueDeserializer<E> for BTreeMap<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<K, V, E> ValueDeserializer<E> for HashMap<K, V>
|
||||
where K: ValueDeserializer<E> + Eq + Hash,
|
||||
V: ValueDeserializer<E>,
|
||||
@@ -618,6 +683,7 @@ impl<'a, E> de::Deserializer for BytesDeserializer<'a, E>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<E> ValueDeserializer<E> for bytes::ByteBuf
|
||||
where E: de::Error,
|
||||
{
|
||||
@@ -629,8 +695,10 @@ impl<E> ValueDeserializer<E> for bytes::ByteBuf
|
||||
}
|
||||
|
||||
/// A helper deserializer that deserializes a `Vec<u8>`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub struct ByteBufDeserializer<E>(Option<Vec<u8>>, PhantomData<E>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<E> de::Deserializer for ByteBufDeserializer<E>
|
||||
where E: de::Error,
|
||||
{
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//! A stand-in for `std::error`
|
||||
use core::any::TypeId;
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
|
||||
/// A stand-in for `std::error::Error`, which requires no allocation.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub trait Error: Debug + Display + ::core::marker::Reflect {
|
||||
/// A short description of the error.
|
||||
///
|
||||
/// The description should not contain newlines or sentence-ending
|
||||
/// punctuation, to facilitate embedding in larger user-facing
|
||||
/// strings.
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// The lower-level cause of this error, if any.
|
||||
fn cause(&self) -> Option<&Error> { None }
|
||||
|
||||
/// Get the `TypeId` of `self`
|
||||
#[doc(hidden)]
|
||||
fn type_id(&self) -> TypeId where Self: 'static {
|
||||
TypeId::of::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
/// A stand-in for `std::error::Error`, which requires no allocation.
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub trait Error: Debug + Display {
|
||||
/// A short description of the error.
|
||||
///
|
||||
/// The description should not contain newlines or sentence-ending
|
||||
/// punctuation, to facilitate embedding in larger user-facing
|
||||
/// strings.
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// The lower-level cause of this error, if any.
|
||||
fn cause(&self) -> Option<&Error> { None }
|
||||
|
||||
/// Stubbed! Returns type_id of `()`
|
||||
#[doc(hidden)]
|
||||
fn type_id(&self) -> TypeId where Self: 'static {
|
||||
TypeId::of::<()>()
|
||||
}
|
||||
}
|
||||
+28
-5
@@ -10,23 +10,46 @@
|
||||
//! [github repository](https://github.com/serde-rs/serde)
|
||||
|
||||
#![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
|
||||
#![cfg_attr(feature = "nightly", feature(collections, enumset, nonzero, plugin, step_trait,
|
||||
zero_one))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(feature = "nightly", feature(reflect_marker, unicode, nonzero, plugin, step_trait, zero_one))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![cfg_attr(feature = "collections", feature(collections, enumset))]
|
||||
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
|
||||
#![cfg_attr(feature = "nightly-testing", allow(linkedlist))]
|
||||
|
||||
#![cfg_attr(any(not(feature = "std"), feature = "nightly"), allow(unused_variables, unused_imports, unused_features, dead_code))]
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
extern crate collections;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
extern crate core;
|
||||
#[cfg(all(feature = "nightly", feature = "alloc"))]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod core {
|
||||
pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize,
|
||||
usize, f32, f64, char, str, num, slice, iter};
|
||||
#[cfg(feature = "nightly")]
|
||||
extern crate core;
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use self::core::nonzero;
|
||||
}
|
||||
|
||||
pub use ser::{Serialize, Serializer};
|
||||
pub use de::{Deserialize, Deserializer, Error};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
macro_rules! format {
|
||||
($s:expr, $($rest:tt)*) => ($s)
|
||||
}
|
||||
|
||||
pub mod bytes;
|
||||
pub mod de;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod iter;
|
||||
pub mod ser;
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub mod error;
|
||||
mod utils;
|
||||
|
||||
+64
-10
@@ -1,6 +1,11 @@
|
||||
//! Implementations for all of Rust's builtin types.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::borrow::Cow;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::{
|
||||
BinaryHeap,
|
||||
BTreeMap,
|
||||
@@ -10,20 +15,47 @@ use std::collections::{
|
||||
HashSet,
|
||||
VecDeque,
|
||||
};
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::{
|
||||
BinaryHeap,
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
LinkedList,
|
||||
VecDeque,
|
||||
String,
|
||||
Vec,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
use collections::enum_set::{CLike, EnumSet};
|
||||
use std::hash::Hash;
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
use collections::borrow::ToOwned;
|
||||
|
||||
use core::hash::{Hash, BuildHasher};
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::iter;
|
||||
use core::iter;
|
||||
#[cfg(feature = "std")]
|
||||
use std::net;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::num;
|
||||
use core::num;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::ops;
|
||||
use core::ops;
|
||||
#[cfg(feature = "std")]
|
||||
use std::path;
|
||||
#[cfg(feature = "std")]
|
||||
use std::rc::Rc;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::rc::Rc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::arc::Arc;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use core::nonzero::{NonZero, Zeroable};
|
||||
@@ -77,6 +109,7 @@ impl Serialize for str {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl Serialize for String {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -260,6 +293,7 @@ array_impls!(32);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T> Serialize for BinaryHeap<T>
|
||||
where T: Serialize + Ord
|
||||
{
|
||||
@@ -271,6 +305,7 @@ impl<T> Serialize for BinaryHeap<T>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T> Serialize for BTreeSet<T>
|
||||
where T: Serialize + Ord,
|
||||
{
|
||||
@@ -282,7 +317,7 @@ impl<T> Serialize for BTreeSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "nightly", feature = "collections"))]
|
||||
impl<T> Serialize for EnumSet<T>
|
||||
where T: Serialize + CLike
|
||||
{
|
||||
@@ -294,8 +329,10 @@ impl<T> Serialize for EnumSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for HashSet<T>
|
||||
#[cfg(feature = "std")]
|
||||
impl<T, H> Serialize for HashSet<T, H>
|
||||
where T: Serialize + Eq + Hash,
|
||||
H: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -305,6 +342,7 @@ impl<T> Serialize for HashSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T> Serialize for LinkedList<T>
|
||||
where T: Serialize,
|
||||
{
|
||||
@@ -330,6 +368,7 @@ impl<A> Serialize for ops::Range<A>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T> Serialize for Vec<T> where T: Serialize {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -339,6 +378,7 @@ impl<T> Serialize for Vec<T> where T: Serialize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<T> Serialize for VecDeque<T> where T: Serialize {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -598,6 +638,7 @@ impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<K, V> Serialize for BTreeMap<K, V>
|
||||
where K: Serialize + Ord,
|
||||
V: Serialize,
|
||||
@@ -610,9 +651,11 @@ impl<K, V> Serialize for BTreeMap<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Serialize for HashMap<K, V>
|
||||
#[cfg(feature = "std")]
|
||||
impl<K, V, H> Serialize for HashMap<K, V, H>
|
||||
where K: Serialize + Eq + Hash,
|
||||
V: Serialize,
|
||||
H: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -642,6 +685,7 @@ impl<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T: ?Sized> Serialize for Box<T> where T: Serialize {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -651,6 +695,7 @@ impl<T: ?Sized> Serialize for Box<T> where T: Serialize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T> Serialize for Rc<T> where T: Serialize, {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -660,6 +705,7 @@ impl<T> Serialize for Rc<T> where T: Serialize, {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<T> Serialize for Arc<T> where T: Serialize, {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -669,6 +715,7 @@ impl<T> Serialize for Arc<T> where T: Serialize, {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned, {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
@@ -695,7 +742,7 @@ impl<T, E> Serialize for Result<T, E> where T: Serialize, E: Serialize {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(all(feature = "std", feature = "nightly"))]
|
||||
impl Serialize for net::IpAddr {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -707,6 +754,7 @@ impl Serialize for net::IpAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for net::Ipv4Addr {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -715,6 +763,7 @@ impl Serialize for net::Ipv4Addr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for net::Ipv6Addr {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -725,6 +774,7 @@ impl Serialize for net::Ipv6Addr {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for net::SocketAddr {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -736,6 +786,7 @@ impl Serialize for net::SocketAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for net::SocketAddrV4 {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -744,6 +795,7 @@ impl Serialize for net::SocketAddrV4 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for net::SocketAddrV6 {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -754,6 +806,7 @@ impl Serialize for net::SocketAddrV6 {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for path::Path {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
@@ -765,6 +818,7 @@ impl Serialize for path::Path {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for path::PathBuf {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer,
|
||||
|
||||
+12
-3
@@ -1,6 +1,12 @@
|
||||
//! Generic serialization framework.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use error;
|
||||
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::String;
|
||||
|
||||
pub mod impls;
|
||||
|
||||
@@ -10,8 +16,13 @@ pub mod impls;
|
||||
/// `Serializer` error.
|
||||
pub trait Error: Sized + error::Error {
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn custom<T: Into<String>>(msg: T) -> Self;
|
||||
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
|
||||
fn custom<T: Into<&'static str>>(msg: T) -> Self;
|
||||
|
||||
/// Raised when a `Serialize` was passed an incorrect value.
|
||||
fn invalid_value(msg: &str) -> Self {
|
||||
Error::custom(format!("invalid value: {}", msg))
|
||||
@@ -115,9 +126,7 @@ pub trait Serializer {
|
||||
/// single character.
|
||||
#[inline]
|
||||
fn serialize_char(&mut self, v: char) -> Result<(), Self::Error> {
|
||||
// FIXME: this allocation is required in order to be compatible with stable rust, which
|
||||
// doesn't support encoding a `char` into a stack buffer.
|
||||
self.serialize_str(&v.to_string())
|
||||
self.serialize_str(::utils::encode_utf8(v).as_str())
|
||||
}
|
||||
|
||||
/// Serializes a `&str`.
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//! Private utility functions
|
||||
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
||||
const MAX_ONE_B: u32 = 0x80;
|
||||
const MAX_TWO_B: u32 = 0x800;
|
||||
const MAX_THREE_B: u32 = 0x10000;
|
||||
|
||||
#[inline]
|
||||
pub fn encode_utf8(c: char) -> EncodeUtf8 {
|
||||
let code = c as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
EncodeUtf8 { buf: buf, pos: pos }
|
||||
}
|
||||
|
||||
pub struct EncodeUtf8 {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl EncodeUtf8 {
|
||||
// FIXME: use this from_utf8_unchecked, since we know it can never fail
|
||||
pub fn as_str(&self) -> &str {
|
||||
::core::str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const Pattern_White_Space_table: &'static [(char, char)] = &[
|
||||
('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'),
|
||||
('\u{2028}', '\u{2029}')
|
||||
];
|
||||
|
||||
fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
r.binary_search_by(|&(lo, hi)| {
|
||||
if c < lo {
|
||||
Greater
|
||||
} else if hi < c {
|
||||
Less
|
||||
} else {
|
||||
Equal
|
||||
}
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Pattern_White_Space(c: char) -> bool {
|
||||
bsearch_range_table(c, Pattern_White_Space_table)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_codegen"
|
||||
version = "0.7.5"
|
||||
version = "0.7.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -8,6 +8,7 @@ repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://github.com/serde-rs/serde"
|
||||
keywords = ["serde", "serialization"]
|
||||
build = "build.rs"
|
||||
include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/lib.rs.in"]
|
||||
|
||||
[features]
|
||||
default = ["with-syntex"]
|
||||
@@ -16,13 +17,13 @@ nightly-testing = ["clippy"]
|
||||
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
||||
|
||||
[build-dependencies]
|
||||
quasi_codegen = { version = "^0.10.0", optional = true }
|
||||
syntex = { version = "^0.32.0", optional = true }
|
||||
quasi_codegen = { version = "^0.12.0", optional = true }
|
||||
syntex = { version = "^0.33.0", optional = true }
|
||||
|
||||
[dependencies]
|
||||
aster = { version = "^0.16.0", default-features = false }
|
||||
aster = { version = "^0.18.0", default-features = false }
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
quasi = { version = "^0.10.0", default-features = false }
|
||||
quasi_macros = { version = "^0.10.0", optional = true }
|
||||
syntex = { version = "^0.32.0", optional = true }
|
||||
syntex_syntax = { version = "^0.32.0", optional = true }
|
||||
quasi = { version = "^0.12.0", default-features = false }
|
||||
quasi_macros = { version = "^0.12.0", optional = true }
|
||||
syntex = { version = "^0.35.0", optional = true }
|
||||
syntex_syntax = { version = "^0.35.0", optional = true }
|
||||
|
||||
@@ -8,13 +8,11 @@ mod inner {
|
||||
|
||||
pub fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let mut registry = syntex::Registry::new();
|
||||
quasi_codegen::register(&mut registry);
|
||||
|
||||
let src = Path::new("src/lib.rs.in");
|
||||
let dst = Path::new(&out_dir).join("lib.rs");
|
||||
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
quasi_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+182
-184
@@ -4,7 +4,7 @@ use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::fold::Folder;
|
||||
use syntax::parse::parser::PathStyle;
|
||||
use syntax::parse::parser::{Parser, PathStyle};
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use syntax::parse;
|
||||
use syntax::print::pprust::{lit_to_string, meta_item_to_string};
|
||||
@@ -62,6 +62,8 @@ impl Name {
|
||||
pub struct ContainerAttrs {
|
||||
name: Name,
|
||||
deny_unknown_fields: bool,
|
||||
ser_bound: Option<Vec<ast::WherePredicate>>,
|
||||
de_bound: Option<Vec<ast::WherePredicate>>,
|
||||
}
|
||||
|
||||
impl ContainerAttrs {
|
||||
@@ -70,6 +72,8 @@ impl ContainerAttrs {
|
||||
let mut container_attrs = ContainerAttrs {
|
||||
name: Name::new(item.ident),
|
||||
deny_unknown_fields: false,
|
||||
ser_bound: None,
|
||||
de_bound: None,
|
||||
};
|
||||
|
||||
for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) {
|
||||
@@ -78,7 +82,6 @@ impl ContainerAttrs {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
|
||||
let s = try!(get_str_from_lit(cx, name, lit));
|
||||
|
||||
container_attrs.name.serialize_name = Some(s.clone());
|
||||
container_attrs.name.deserialize_name = Some(s);
|
||||
}
|
||||
@@ -86,9 +89,12 @@ impl ContainerAttrs {
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
|
||||
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||
|
||||
container_attrs.name.serialize_name = ser_name;
|
||||
container_attrs.name.deserialize_name = de_name;
|
||||
if ser_name.is_some() {
|
||||
container_attrs.name.serialize_name = ser_name;
|
||||
}
|
||||
if de_name.is_some() {
|
||||
container_attrs.name.deserialize_name = de_name;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deny_unknown_fields)]`
|
||||
@@ -96,6 +102,24 @@ impl ContainerAttrs {
|
||||
container_attrs.deny_unknown_fields = true;
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => {
|
||||
let where_predicates = try!(parse_lit_into_where(cx, name, lit));
|
||||
container_attrs.ser_bound = Some(where_predicates.clone());
|
||||
container_attrs.de_bound = Some(where_predicates);
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => {
|
||||
let (ser_bound, de_bound) = try!(get_where_predicates(cx, meta_items));
|
||||
if ser_bound.is_some() {
|
||||
container_attrs.ser_bound = ser_bound;
|
||||
}
|
||||
if de_bound.is_some() {
|
||||
container_attrs.de_bound = de_bound;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
@@ -118,6 +142,14 @@ impl ContainerAttrs {
|
||||
pub fn deny_unknown_fields(&self) -> bool {
|
||||
self.deny_unknown_fields
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[ast::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[ast::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents variant attribute information
|
||||
@@ -138,7 +170,6 @@ impl VariantAttrs {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
|
||||
let s = try!(get_str_from_lit(cx, name, lit));
|
||||
|
||||
variant_attrs.name.serialize_name = Some(s.clone());
|
||||
variant_attrs.name.deserialize_name = Some(s);
|
||||
}
|
||||
@@ -146,9 +177,12 @@ impl VariantAttrs {
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
|
||||
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||
|
||||
variant_attrs.name.serialize_name = ser_name;
|
||||
variant_attrs.name.deserialize_name = de_name;
|
||||
if ser_name.is_some() {
|
||||
variant_attrs.name.serialize_name = ser_name;
|
||||
}
|
||||
if de_name.is_some() {
|
||||
variant_attrs.name.deserialize_name = de_name;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
@@ -177,34 +211,47 @@ pub struct FieldAttrs {
|
||||
name: Name,
|
||||
skip_serializing_field: bool,
|
||||
skip_deserializing_field: bool,
|
||||
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||
serialize_with: Option<P<ast::Expr>>,
|
||||
skip_serializing_if: Option<ast::Path>,
|
||||
default: FieldDefault,
|
||||
serialize_with: Option<ast::Path>,
|
||||
deserialize_with: Option<ast::Path>,
|
||||
ser_bound: Option<Vec<ast::WherePredicate>>,
|
||||
de_bound: Option<Vec<ast::WherePredicate>>,
|
||||
}
|
||||
|
||||
/// Represents the default to use for a field when deserializing.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum FieldDefault {
|
||||
/// Field must always be specified because it does not have a default.
|
||||
None,
|
||||
/// The default is given by `std::default::Default::default()`.
|
||||
Default,
|
||||
/// The default is given by this function.
|
||||
Path(ast::Path),
|
||||
}
|
||||
|
||||
impl FieldAttrs {
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn from_field(cx: &ExtCtxt,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
field: &ast::StructField,
|
||||
is_enum: bool) -> Result<Self, Error> {
|
||||
index: usize,
|
||||
field: &ast::StructField) -> Result<Self, Error> {
|
||||
let builder = AstBuilder::new();
|
||||
|
||||
let field_ident = match field.ident {
|
||||
Some(ident) => ident,
|
||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||
None => builder.id(index.to_string()),
|
||||
};
|
||||
|
||||
let mut field_attrs = FieldAttrs {
|
||||
name: Name::new(field_ident),
|
||||
skip_serializing_field: false,
|
||||
skip_deserializing_field: false,
|
||||
skip_serializing_field_if: None,
|
||||
default_expr_if_missing: None,
|
||||
skip_serializing_if: None,
|
||||
default: FieldDefault::None,
|
||||
serialize_with: None,
|
||||
deserialize_with: None,
|
||||
ser_bound: None,
|
||||
de_bound: None,
|
||||
};
|
||||
|
||||
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
@@ -213,7 +260,6 @@ impl FieldAttrs {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
|
||||
let s = try!(get_str_from_lit(cx, name, lit));
|
||||
|
||||
field_attrs.name.serialize_name = Some(s.clone());
|
||||
field_attrs.name.deserialize_name = Some(s);
|
||||
}
|
||||
@@ -221,24 +267,23 @@ impl FieldAttrs {
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
|
||||
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||
|
||||
field_attrs.name.serialize_name = ser_name;
|
||||
field_attrs.name.deserialize_name = de_name;
|
||||
if ser_name.is_some() {
|
||||
field_attrs.name.serialize_name = ser_name;
|
||||
}
|
||||
if de_name.is_some() {
|
||||
field_attrs.name.deserialize_name = de_name;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(default)]`
|
||||
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
||||
let default_expr = builder.expr().default();
|
||||
field_attrs.default_expr_if_missing = Some(default_expr);
|
||||
field_attrs.default = FieldDefault::Default;
|
||||
}
|
||||
|
||||
// Parse `#[serde(default="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => {
|
||||
let wrapped_expr = wrap_default(
|
||||
try!(parse_lit_into_path(cx, name, lit)),
|
||||
);
|
||||
|
||||
field_attrs.default_expr_if_missing = Some(wrapped_expr);
|
||||
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||
field_attrs.default = FieldDefault::Path(path);
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing)]`
|
||||
@@ -252,35 +297,21 @@ impl FieldAttrs {
|
||||
|
||||
// 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);
|
||||
if field_attrs.default == FieldDefault::None {
|
||||
field_attrs.default = FieldDefault::Default;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing_if="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
||||
let expr = wrap_skip_serializing(
|
||||
field_ident,
|
||||
try!(parse_lit_into_path(cx, name, lit)),
|
||||
is_enum,
|
||||
);
|
||||
|
||||
field_attrs.skip_serializing_field_if = Some(expr);
|
||||
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||
field_attrs.skip_serializing_if = Some(path);
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => {
|
||||
let expr = wrap_serialize_with(
|
||||
cx,
|
||||
container_ty,
|
||||
generics,
|
||||
field_ident,
|
||||
try!(parse_lit_into_path(cx, name, lit)),
|
||||
is_enum,
|
||||
);
|
||||
|
||||
field_attrs.serialize_with = Some(expr);
|
||||
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||
field_attrs.serialize_with = Some(path);
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with="...")]`
|
||||
@@ -289,6 +320,24 @@ impl FieldAttrs {
|
||||
field_attrs.deserialize_with = Some(path);
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => {
|
||||
let where_predicates = try!(parse_lit_into_where(cx, name, lit));
|
||||
field_attrs.ser_bound = Some(where_predicates.clone());
|
||||
field_attrs.de_bound = Some(where_predicates);
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => {
|
||||
let (ser_bound, de_bound) = try!(get_where_predicates(cx, meta_items));
|
||||
if ser_bound.is_some() {
|
||||
field_attrs.ser_bound = ser_bound;
|
||||
}
|
||||
if de_bound.is_some() {
|
||||
field_attrs.de_bound = de_bound;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
@@ -316,57 +365,74 @@ impl FieldAttrs {
|
||||
self.skip_deserializing_field
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
||||
self.skip_serializing_field_if.as_ref()
|
||||
pub fn skip_serializing_if(&self) -> Option<&ast::Path> {
|
||||
self.skip_serializing_if.as_ref()
|
||||
}
|
||||
|
||||
pub fn default_expr_if_missing(&self) -> Option<&P<ast::Expr>> {
|
||||
self.default_expr_if_missing.as_ref()
|
||||
pub fn default(&self) -> &FieldDefault {
|
||||
&self.default
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||
pub fn serialize_with(&self) -> Option<&ast::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&ast::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[ast::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[ast::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
fields: &[ast::StructField],
|
||||
is_enum: bool) -> Result<Vec<FieldAttrs>, Error> {
|
||||
/// Zip together fields and `#[serde(...)]` attributes on those fields.
|
||||
pub fn fields_with_attrs(
|
||||
cx: &ExtCtxt,
|
||||
fields: &[ast::StructField],
|
||||
) -> Result<Vec<(ast::StructField, FieldAttrs)>, Error> {
|
||||
fields.iter()
|
||||
.map(|field| FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
let attrs = try!(FieldAttrs::from_field(cx, i, field));
|
||||
Ok((field.clone(), attrs))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_renames(cx: &ExtCtxt,
|
||||
items: &[P<ast::MetaItem>],
|
||||
)-> Result<(Option<InternedString>, Option<InternedString>), Error> {
|
||||
let mut ser_name = None;
|
||||
let mut de_name = None;
|
||||
fn get_ser_and_de<T, F>(
|
||||
cx: &ExtCtxt,
|
||||
attribute: &str,
|
||||
items: &[P<ast::MetaItem>],
|
||||
f: F
|
||||
) -> Result<(Option<T>, Option<T>), Error>
|
||||
where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result<T, Error>,
|
||||
{
|
||||
let mut ser_item = None;
|
||||
let mut de_item = None;
|
||||
|
||||
for item in items {
|
||||
match item.node {
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => {
|
||||
let s = try!(get_str_from_lit(cx, name, lit));
|
||||
ser_name = Some(s);
|
||||
let s = try!(f(cx, name, lit));
|
||||
ser_item = Some(s);
|
||||
}
|
||||
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => {
|
||||
let s = try!(get_str_from_lit(cx, name, lit));
|
||||
de_name = Some(s);
|
||||
let s = try!(f(cx, name, lit));
|
||||
de_item = Some(s);
|
||||
}
|
||||
|
||||
_ => {
|
||||
cx.span_err(
|
||||
item.span,
|
||||
&format!("unknown rename attribute `{}`",
|
||||
&format!("unknown {} attribute `{}`",
|
||||
attribute,
|
||||
meta_item_to_string(item)));
|
||||
|
||||
return Err(Error);
|
||||
@@ -374,7 +440,21 @@ fn get_renames(cx: &ExtCtxt,
|
||||
}
|
||||
}
|
||||
|
||||
Ok((ser_name, de_name))
|
||||
Ok((ser_item, de_item))
|
||||
}
|
||||
|
||||
fn get_renames(
|
||||
cx: &ExtCtxt,
|
||||
items: &[P<ast::MetaItem>],
|
||||
) -> Result<(Option<InternedString>, Option<InternedString>), Error> {
|
||||
get_ser_and_de(cx, "rename", items, get_str_from_lit)
|
||||
}
|
||||
|
||||
fn get_where_predicates(
|
||||
cx: &ExtCtxt,
|
||||
items: &[P<ast::MetaItem>],
|
||||
) -> Result<(Option<Vec<ast::WherePredicate>>, Option<Vec<ast::WherePredicate>>), Error> {
|
||||
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
|
||||
}
|
||||
|
||||
pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
||||
@@ -449,17 +529,18 @@ fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<Interned
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::Path, Error> {
|
||||
let source = try!(get_str_from_lit(cx, name, lit));
|
||||
|
||||
// If we just parse the string into an expression, any syntax errors in the source will only
|
||||
// have spans that point inside the string, and not back to the attribute. So to have better
|
||||
// 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,
|
||||
// and then finally parse them into an expression.
|
||||
// If we just parse a string literal from an attibute, any syntax errors in the
|
||||
// source will only have spans that point inside the string and not back to the
|
||||
// attribute. So to have better 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 attribnute, and then finally
|
||||
// parse them into an expression or where-clause.
|
||||
fn parse_string_via_tts<T, F>(cx: &ExtCtxt, name: &str, string: String, action: F) -> Result<T, Error>
|
||||
where F: for<'a> Fn(&'a mut Parser) -> parse::PResult<'a, T>,
|
||||
{
|
||||
let tts = panictry!(parse::parse_tts_from_source_str(
|
||||
format!("<serde {} expansion>", name),
|
||||
(*source).to_owned(),
|
||||
string,
|
||||
cx.cfg(),
|
||||
cx.parse_sess()));
|
||||
|
||||
@@ -468,7 +549,7 @@ fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::
|
||||
|
||||
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts);
|
||||
|
||||
let path = match parser.parse_path(PathStyle::Type) {
|
||||
let path = match action(&mut parser) {
|
||||
Ok(path) => path,
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
@@ -488,107 +569,24 @@ fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// This function wraps the expression in `#[serde(default="...")]` in a function to prevent it
|
||||
/// from accessing the internal `Deserialize` state.
|
||||
fn wrap_default(path: ast::Path) -> P<ast::Expr> {
|
||||
AstBuilder::new().expr().call()
|
||||
.build_path(path)
|
||||
.build()
|
||||
}
|
||||
fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::Path, Error> {
|
||||
let string = try!(get_str_from_lit(cx, name, lit)).to_string();
|
||||
|
||||
/// This function wraps the expression in `#[serde(skip_serializing_if="...")]` in a trait to
|
||||
/// prevent it from accessing the internal `Serialize` state.
|
||||
fn wrap_skip_serializing(field_ident: ast::Ident,
|
||||
path: ast::Path,
|
||||
is_enum: bool) -> P<ast::Expr> {
|
||||
let builder = AstBuilder::new();
|
||||
|
||||
let expr = builder.expr()
|
||||
.field(field_ident)
|
||||
.field("value")
|
||||
.self_();
|
||||
|
||||
let expr = if is_enum {
|
||||
expr
|
||||
} else {
|
||||
builder.expr().ref_().build(expr)
|
||||
};
|
||||
|
||||
builder.expr().call()
|
||||
.build_path(path)
|
||||
.arg().build(expr)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// This function wraps the expression in `#[serde(serialize_with="...")]` in a trait to
|
||||
/// prevent it from accessing the internal `Serialize` state.
|
||||
fn wrap_serialize_with(cx: &ExtCtxt,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
field_ident: ast::Ident,
|
||||
path: ast::Path,
|
||||
is_enum: bool) -> P<ast::Expr> {
|
||||
let builder = AstBuilder::new();
|
||||
|
||||
let expr = builder.expr()
|
||||
.field(field_ident)
|
||||
.self_();
|
||||
|
||||
let expr = if is_enum {
|
||||
expr
|
||||
} else {
|
||||
builder.expr().ref_().build(expr)
|
||||
};
|
||||
|
||||
let expr = builder.expr().call()
|
||||
.build_path(path)
|
||||
.arg().build(expr)
|
||||
.arg()
|
||||
.id("serializer")
|
||||
.build();
|
||||
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
quote_expr!(cx, {
|
||||
trait __SerdeSerializeWith {
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer;
|
||||
}
|
||||
|
||||
impl<'__a, __T> __SerdeSerializeWith for &'__a __T
|
||||
where __T: '__a + __SerdeSerializeWith,
|
||||
{
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
(**self).__serde_serialize_with(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl $generics __SerdeSerializeWith for $container_ty $where_clause {
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
$expr
|
||||
}
|
||||
}
|
||||
|
||||
struct __SerdeSerializeWithStruct<'__a, __T: '__a> {
|
||||
value: &'__a __T,
|
||||
}
|
||||
|
||||
impl<'__a, __T> _serde::ser::Serialize for __SerdeSerializeWithStruct<'__a, __T>
|
||||
where __T: '__a + __SerdeSerializeWith
|
||||
{
|
||||
fn serialize<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
self.value.__serde_serialize_with(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
__SerdeSerializeWithStruct {
|
||||
value: &self.value,
|
||||
}
|
||||
parse_string_via_tts(cx, name, string, |parser| {
|
||||
parser.parse_path(PathStyle::Type)
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_lit_into_where(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<Vec<ast::WherePredicate>, Error> {
|
||||
let string = try!(get_str_from_lit(cx, name, lit));
|
||||
if string.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let where_string = format!("where {}", string);
|
||||
|
||||
parse_string_via_tts(cx, name, where_string, |parser| {
|
||||
let where_clause = try!(parser.parse_where_clause());
|
||||
Ok(where_clause.predicates)
|
||||
})
|
||||
}
|
||||
|
||||
+105
-14
@@ -7,6 +7,9 @@ use syntax::ext::base::ExtCtxt;
|
||||
use syntax::ptr::P;
|
||||
use syntax::visit;
|
||||
|
||||
use attr;
|
||||
use error::Error;
|
||||
|
||||
// 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".
|
||||
@@ -21,22 +24,53 @@ pub fn without_defaults(generics: &ast::Generics) -> ast::Generics {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_bound(
|
||||
pub fn with_where_predicates(
|
||||
builder: &AstBuilder,
|
||||
generics: &ast::Generics,
|
||||
predicates: &[ast::WherePredicate],
|
||||
) -> ast::Generics {
|
||||
builder.from_generics(generics.clone())
|
||||
.with_predicates(predicates.to_vec())
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn with_where_predicates_from_fields<F>(
|
||||
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())
|
||||
from_field: F,
|
||||
) -> Result<ast::Generics, Error>
|
||||
where F: Fn(&attr::FieldAttrs) -> Option<&[ast::WherePredicate]>,
|
||||
{
|
||||
Ok(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)
|
||||
try!(all_fields_with_attrs(cx, item))
|
||||
.iter()
|
||||
.flat_map(|&(_, ref attrs)| from_field(attrs))
|
||||
.flat_map(|predicates| predicates.to_vec()))
|
||||
.build())
|
||||
}
|
||||
|
||||
pub fn with_bound<F>(
|
||||
cx: &ExtCtxt,
|
||||
builder: &AstBuilder,
|
||||
item: &ast::Item,
|
||||
generics: &ast::Generics,
|
||||
filter: F,
|
||||
bound: &ast::Path,
|
||||
) -> Result<ast::Generics, Error>
|
||||
where F: Fn(&attr::FieldAttrs) -> bool,
|
||||
{
|
||||
Ok(builder.from_generics(generics.clone())
|
||||
.with_predicates(
|
||||
try!(all_fields_with_attrs(cx, item))
|
||||
.iter()
|
||||
.filter(|&&(_, ref attrs)| filter(attrs))
|
||||
.map(|&(ref field, _)| &field.ty)
|
||||
// TODO this filter can be removed later, see comment on function
|
||||
.filter(|ty| contains_generic(ty, generics))
|
||||
.filter(|ty| !contains_recursion(ty, item.ident))
|
||||
.map(|ty| strip_reference(ty))
|
||||
.map(|ty| builder.where_predicate()
|
||||
// the type that is being bounded e.g. T
|
||||
@@ -44,7 +78,20 @@ pub fn with_bound(
|
||||
// the bound e.g. Serialize
|
||||
.bound().trait_(bound.clone()).build()
|
||||
.build()))
|
||||
.build()
|
||||
.build())
|
||||
}
|
||||
|
||||
fn all_fields_with_attrs(
|
||||
cx: &ExtCtxt,
|
||||
item: &ast::Item,
|
||||
) -> Result<Vec<(ast::StructField, attr::FieldAttrs)>, Error> {
|
||||
let fields: Vec<ast::StructField> =
|
||||
all_variants(cx, item).iter()
|
||||
.flat_map(|variant_data| all_struct_fields(variant_data))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
attr::fields_with_attrs(cx, &fields)
|
||||
}
|
||||
|
||||
fn all_variants<'a>(cx: &ExtCtxt, item: &'a ast::Item) -> Vec<&'a ast::VariantData> {
|
||||
@@ -113,6 +160,50 @@ fn contains_generic(ty: &ast::Ty, generics: &ast::Generics) -> bool {
|
||||
visitor.found_generic
|
||||
}
|
||||
|
||||
// We do not attempt to generate any bounds based on field types that are
|
||||
// directly recursive, as in:
|
||||
//
|
||||
// struct Test<D> {
|
||||
// next: Box<Test<D>>,
|
||||
// }
|
||||
//
|
||||
// This does not catch field types that are mutually recursive with some other
|
||||
// type. For those, we require bounds to be specified by a `bound` attribute if
|
||||
// the inferred ones are not correct.
|
||||
//
|
||||
// struct Test<D> {
|
||||
// #[serde(bound="D: Serialize + Deserialize")]
|
||||
// next: Box<Other<D>>,
|
||||
// }
|
||||
// struct Other<D> {
|
||||
// #[serde(bound="D: Serialize + Deserialize")]
|
||||
// next: Box<Test<D>>,
|
||||
// }
|
||||
fn contains_recursion(ty: &ast::Ty, ident: ast::Ident) -> bool {
|
||||
struct FindRecursion {
|
||||
ident: ast::Ident,
|
||||
found_recursion: bool,
|
||||
}
|
||||
impl<'v> visit::Visitor<'v> for FindRecursion {
|
||||
fn visit_path(&mut self, path: &'v ast::Path, _id: ast::NodeId) {
|
||||
if !path.global
|
||||
&& path.segments.len() == 1
|
||||
&& path.segments[0].identifier == self.ident {
|
||||
self.found_recursion = true;
|
||||
} else {
|
||||
visit::walk_path(self, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = FindRecursion {
|
||||
ident: ident,
|
||||
found_recursion: false,
|
||||
};
|
||||
visit::walk_ty(&mut visitor, ty);
|
||||
visitor.found_recursion
|
||||
}
|
||||
|
||||
// This is required to handle types that use both a reference and a value of
|
||||
// the same type, as in:
|
||||
//
|
||||
@@ -139,9 +230,9 @@ fn contains_generic(ty: &ast::Ty, generics: &ast::Generics) -> bool {
|
||||
//
|
||||
// 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
|
||||
fn strip_reference(mut ty: &P<ast::Ty>) -> &P<ast::Ty> {
|
||||
while let ast::TyKind::Rptr(_, ref mut_ty) = ty.node {
|
||||
ty = &mut_ty.ty;
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
||||
+253
-344
@@ -9,7 +9,6 @@ use syntax::ast::{
|
||||
};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::ptr::P;
|
||||
|
||||
@@ -36,36 +35,53 @@ pub fn expand_derive_deserialize(
|
||||
|
||||
let builder = aster::AstBuilder::new().span(span);
|
||||
|
||||
let generics = match item.node {
|
||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
"`#[derive(Deserialize)]` may only be applied to structs and enums");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let impl_generics = build_impl_generics(cx, &builder, item, generics);
|
||||
|
||||
let ty = builder.ty().path()
|
||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||
.build();
|
||||
|
||||
let body = match deserialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
|
||||
Ok(body) => body,
|
||||
let impl_item = match deserialize_item(cx, &builder, &item) {
|
||||
Ok(item) => item,
|
||||
Err(Error) => {
|
||||
// An error occured, but it should have been reported already.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
push(Annotatable::Item(impl_item))
|
||||
}
|
||||
|
||||
fn deserialize_item(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
item: &Item,
|
||||
) -> Result<P<ast::Item>, Error> {
|
||||
let generics = match item.node {
|
||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||
_ => {
|
||||
cx.span_err(
|
||||
item.span,
|
||||
"`#[derive(Deserialize)]` may only be applied to structs and enums");
|
||||
return Err(Error);
|
||||
}
|
||||
};
|
||||
|
||||
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||
|
||||
let impl_generics = try!(build_impl_generics(cx, &builder, item, generics, &container_attrs));
|
||||
|
||||
let ty = builder.ty().path()
|
||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||
.build();
|
||||
|
||||
let body = try!(deserialize_body(cx,
|
||||
&builder,
|
||||
&item,
|
||||
&impl_generics,
|
||||
ty.clone(),
|
||||
&container_attrs));
|
||||
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let dummy_const = builder.id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident));
|
||||
|
||||
let impl_item = quote_item!(cx,
|
||||
Ok(quote_item!(cx,
|
||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||
const $dummy_const: () = {
|
||||
extern crate serde as _serde;
|
||||
@@ -78,9 +94,7 @@ pub fn expand_derive_deserialize(
|
||||
}
|
||||
}
|
||||
};
|
||||
).unwrap();
|
||||
|
||||
push(Annotatable::Item(impl_item))
|
||||
).unwrap())
|
||||
}
|
||||
|
||||
// All the generics in the input, plus a bound `T: Deserialize` for each generic
|
||||
@@ -91,58 +105,45 @@ fn build_impl_generics(
|
||||
builder: &aster::AstBuilder,
|
||||
item: &Item,
|
||||
generics: &ast::Generics,
|
||||
) -> ast::Generics {
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<ast::Generics, Error> {
|
||||
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
|
||||
|
||||
let generics = try!(bound::with_where_predicates_from_fields(
|
||||
cx, builder, item, &generics,
|
||||
|attrs| attrs.de_bound()));
|
||||
|
||||
match container_attrs.de_bound() {
|
||||
Some(predicates) => {
|
||||
let generics = bound::with_where_predicates(builder, &generics, predicates);
|
||||
Ok(generics)
|
||||
}
|
||||
None => {
|
||||
let generics = try!(bound::with_bound(cx, builder, item, &generics,
|
||||
needs_deserialize_bound,
|
||||
&builder.path().ids(&["_serde", "de", "Deserialize"]).build()));
|
||||
let generics = try!(bound::with_bound(cx, builder, item, &generics,
|
||||
requires_default,
|
||||
&builder.path().global().ids(&["std", "default", "Default"]).build()));
|
||||
Ok(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
|
||||
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Deserialize` bound where T is the type of the field.
|
||||
fn needs_deserialize_bound(attrs: &attr::FieldAttrs) -> bool {
|
||||
!attrs.skip_deserializing_field()
|
||||
&& attrs.deserialize_with().is_none()
|
||||
&& attrs.de_bound().is_none()
|
||||
}
|
||||
|
||||
// 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 requires_default(attrs: &attr::FieldAttrs) -> bool {
|
||||
attrs.default() == &attr::FieldDefault::Default
|
||||
}
|
||||
|
||||
fn deserialize_body(
|
||||
@@ -151,9 +152,8 @@ fn deserialize_body(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||
|
||||
match item.node {
|
||||
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||
deserialize_item_struct(
|
||||
@@ -164,7 +164,7 @@ fn deserialize_body(
|
||||
ty,
|
||||
item.span,
|
||||
variant_data,
|
||||
&container_attrs,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
@@ -175,7 +175,7 @@ fn deserialize_body(
|
||||
impl_generics,
|
||||
ty,
|
||||
enum_def,
|
||||
&container_attrs,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
@@ -203,28 +203,19 @@ fn deserialize_item_struct(
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
deserialize_newtype_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
impl_generics,
|
||||
ty,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
if fields.iter().any(|field| field.ident.is_some()) {
|
||||
cx.span_bug(span, "tuple struct has named fields")
|
||||
}
|
||||
|
||||
deserialize_tuple_struct(
|
||||
deserialize_tuple(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
None,
|
||||
impl_generics,
|
||||
ty,
|
||||
fields.len(),
|
||||
fields,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
@@ -237,6 +228,7 @@ fn deserialize_item_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
None,
|
||||
impl_generics,
|
||||
ty,
|
||||
fields,
|
||||
@@ -360,12 +352,14 @@ fn deserialize_unit_struct(
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(
|
||||
fn deserialize_tuple(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
variant_ident: Option<Ident>,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
@@ -377,67 +371,50 @@ fn deserialize_newtype_struct(
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
let is_enum = variant_ident.is_some();
|
||||
let type_path = match variant_ident {
|
||||
Some(variant_ident) => builder.path().id(type_ident).id(variant_ident).build(),
|
||||
None => builder.path().id(type_ident).build(),
|
||||
};
|
||||
|
||||
let nfields = fields.len();
|
||||
let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
|
||||
|
||||
let visit_newtype_struct = if !is_enum && nfields == 1 {
|
||||
Some(try!(deserialize_newtype_struct(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
&type_path,
|
||||
impl_generics,
|
||||
&fields_with_attrs[0],
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let visit_seq_expr = try!(deserialize_seq(
|
||||
cx,
|
||||
builder,
|
||||
builder.path().id(type_ident).build(),
|
||||
1,
|
||||
);
|
||||
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
|
||||
type Value = $ty;
|
||||
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(&mut self, deserializer: &mut __E) -> ::std::result::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::de::Deserializer,
|
||||
{
|
||||
let value = try!(_serde::de::Deserialize::deserialize(deserializer));
|
||||
Ok($type_ident(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||
where __V: _serde::de::SeqVisitor,
|
||||
{
|
||||
$visit_seq_expr
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_newtype_struct($type_name, $visitor_expr)
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
builder,
|
||||
type_ident,
|
||||
type_path,
|
||||
impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
&fields_with_attrs,
|
||||
false,
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
builder,
|
||||
builder.path().id(type_ident).build(),
|
||||
fields,
|
||||
);
|
||||
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
let dispatch = if is_enum {
|
||||
quote_expr!(cx,
|
||||
visitor.visit_tuple($nfields, $visitor_expr))
|
||||
} else if nfields == 1 {
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
quote_expr!(cx,
|
||||
deserializer.deserialize_newtype_struct($type_name, $visitor_expr))
|
||||
} else {
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
quote_expr!(cx,
|
||||
deserializer.deserialize_tuple_struct($type_name, $nfields, $visitor_expr))
|
||||
};
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
@@ -445,6 +422,8 @@ fn deserialize_tuple_struct(
|
||||
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
|
||||
type Value = $ty;
|
||||
|
||||
$visit_newtype_struct
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||
where __V: _serde::de::SeqVisitor,
|
||||
@@ -453,55 +432,22 @@ fn deserialize_tuple_struct(
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_tuple_struct($type_name, $fields, $visitor_expr)
|
||||
$dispatch
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_seq(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
fields: usize,
|
||||
) -> P<ast::Expr> {
|
||||
let let_values: Vec<ast::Stmt> = (0 .. fields)
|
||||
.map(|i| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
quote_stmt!(cx,
|
||||
let $name = match try!(visitor.visit()) {
|
||||
Some(value) => { value },
|
||||
None => {
|
||||
return Err(_serde::de::Error::end_of_stream());
|
||||
}
|
||||
};
|
||||
).unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let result = builder.expr().call()
|
||||
.build_path(struct_path)
|
||||
.with_args((0 .. fields).map(|i| builder.expr().id(format!("__field{}", i))))
|
||||
.build();
|
||||
|
||||
quote_expr!(cx, {
|
||||
$let_values
|
||||
|
||||
try!(visitor.end());
|
||||
|
||||
Ok($result)
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_struct_as_seq(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
type_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
fields: &[(ast::StructField, attr::FieldAttrs)],
|
||||
is_struct: bool,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let let_values: Vec<_> = fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(field, ref attrs))| {
|
||||
.map(|(i, &(ref field, ref attrs))| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
if attrs.skip_deserializing_field() {
|
||||
let default = expr_is_missing(cx, attrs);
|
||||
@@ -536,23 +482,30 @@ fn deserialize_struct_as_seq(
|
||||
})
|
||||
.collect();
|
||||
|
||||
let result = builder.expr().struct_path(struct_path)
|
||||
.with_id_exprs(
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(field, _))| {
|
||||
(
|
||||
match field.ident {
|
||||
Some(name) => name.clone(),
|
||||
None => {
|
||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||
}
|
||||
},
|
||||
builder.expr().id(format!("__field{}", i)),
|
||||
)
|
||||
})
|
||||
)
|
||||
.build();
|
||||
let result = if is_struct {
|
||||
builder.expr().struct_path(type_path)
|
||||
.with_id_exprs(
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(ref field, _))| {
|
||||
(
|
||||
match field.ident {
|
||||
Some(name) => name.clone(),
|
||||
None => {
|
||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||
}
|
||||
},
|
||||
builder.expr().id(format!("__field{}", i)),
|
||||
)
|
||||
})
|
||||
)
|
||||
.build()
|
||||
} else {
|
||||
builder.expr().call()
|
||||
.build_path(type_path)
|
||||
.with_args((0..fields.len()).map(|i| builder.expr().id(format!("__field{}", i))))
|
||||
.build()
|
||||
};
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$let_values
|
||||
@@ -563,10 +516,46 @@ fn deserialize_struct_as_seq(
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
type_path: &ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
field: &(ast::StructField, attr::FieldAttrs),
|
||||
) -> Result<Vec<ast::TokenTree>, Error> {
|
||||
let &(ref field, ref attrs) = field;
|
||||
let value = match attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote_expr!(cx,
|
||||
try!(<$field_ty as _serde::Deserialize>::deserialize(__e)))
|
||||
}
|
||||
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!(<$wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
||||
})
|
||||
}
|
||||
};
|
||||
Ok(quote_tokens!(cx,
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(&mut self, __e: &mut __E) -> ::std::result::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::de::Deserializer,
|
||||
{
|
||||
Ok($type_path($value))
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
fn deserialize_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
variant_ident: Option<Ident>,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
@@ -581,17 +570,21 @@ fn deserialize_struct(
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
let type_path = builder.path().id(type_ident).build();
|
||||
let type_path = match variant_ident {
|
||||
Some(variant_ident) => builder.path().id(type_ident).id(variant_ident).build(),
|
||||
None => builder.path().id(type_ident).build(),
|
||||
};
|
||||
|
||||
let fields_with_attrs = try!(fields_with_attrs(cx, impl_generics, &ty, fields, false));
|
||||
let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
|
||||
|
||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||
let visit_seq_expr = try!(deserialize_seq(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path.clone(),
|
||||
impl_generics,
|
||||
&fields_with_attrs,
|
||||
true,
|
||||
));
|
||||
|
||||
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
||||
@@ -604,7 +597,15 @@ fn deserialize_struct(
|
||||
container_attrs,
|
||||
));
|
||||
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
let is_enum = variant_ident.is_some();
|
||||
let dispatch = if is_enum {
|
||||
quote_expr!(cx,
|
||||
visitor.visit_struct(FIELDS, $visitor_expr))
|
||||
} else {
|
||||
let type_name = container_attrs.name().deserialize_name_expr();
|
||||
quote_expr!(cx,
|
||||
deserializer.deserialize_struct($type_name, FIELDS, $visitor_expr))
|
||||
};
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$field_visitor
|
||||
@@ -631,7 +632,7 @@ fn deserialize_struct(
|
||||
|
||||
$fields_stmt
|
||||
|
||||
deserializer.deserialize_struct($type_name, FIELDS, $visitor_expr)
|
||||
$dispatch
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -752,29 +753,34 @@ fn deserialize_variant(
|
||||
Ok($type_ident::$variant_ident)
|
||||
}))
|
||||
}
|
||||
ast::VariantData::Tuple(ref args, _) if args.len() == 1 => {
|
||||
Ok(quote_expr!(cx, {
|
||||
let val = try!(visitor.visit_newtype());
|
||||
Ok($type_ident::$variant_ident(val))
|
||||
}))
|
||||
}
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
deserialize_tuple_variant(
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
deserialize_newtype_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
variant_ident,
|
||||
generics,
|
||||
ty,
|
||||
fields.len(),
|
||||
&fields[0],
|
||||
)
|
||||
}
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
deserialize_struct_variant(
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
deserialize_tuple(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
variant_ident,
|
||||
Some(variant_ident),
|
||||
generics,
|
||||
ty,
|
||||
fields,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
deserialize_struct(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
Some(variant_ident),
|
||||
generics,
|
||||
ty,
|
||||
fields,
|
||||
@@ -784,120 +790,31 @@ fn deserialize_variant(
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_tuple_variant(
|
||||
fn deserialize_newtype_variant(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: ast::Ident,
|
||||
variant_ident: ast::Ident,
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
type_ident: Ident,
|
||||
variant_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
field: &ast::StructField,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
builder,
|
||||
builder.path().id(type_ident).id(variant_ident).build(),
|
||||
fields,
|
||||
);
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
|
||||
type Value = $ty;
|
||||
|
||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||
where __V: _serde::de::SeqVisitor,
|
||||
{
|
||||
$visit_seq_expr
|
||||
}
|
||||
let attrs = try!(attr::FieldAttrs::from_field(cx, 0, field));
|
||||
let visit = match attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote_expr!(cx, try!(visitor.visit_newtype::<$field_ty>()))
|
||||
}
|
||||
|
||||
visitor.visit_tuple($fields, $visitor_expr)
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_struct_variant(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: ast::Ident,
|
||||
variant_ident: ast::Ident,
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let type_path = builder.path()
|
||||
.id(type_ident)
|
||||
.id(variant_ident)
|
||||
.build();
|
||||
|
||||
let fields_with_attrs = try!(fields_with_attrs(cx, generics, &ty, fields, true));
|
||||
|
||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path.clone(),
|
||||
generics,
|
||||
&fields_with_attrs,
|
||||
));
|
||||
|
||||
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path,
|
||||
generics,
|
||||
&fields_with_attrs,
|
||||
container_attrs,
|
||||
));
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
builder,
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
));
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$field_visitor
|
||||
|
||||
$visitor_item
|
||||
|
||||
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
|
||||
type Value = $ty;
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||
where __V: _serde::de::SeqVisitor,
|
||||
{
|
||||
$visit_seq_expr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||
where __V: _serde::de::MapVisitor,
|
||||
{
|
||||
$field_expr
|
||||
}
|
||||
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_newtype::<$wrapper_ty>()).value
|
||||
})
|
||||
}
|
||||
|
||||
$fields_stmt
|
||||
|
||||
visitor.visit_struct(FIELDS, $visitor_expr)
|
||||
}))
|
||||
};
|
||||
Ok(quote_expr!(cx, Ok($type_ident::$variant_ident($visit))))
|
||||
}
|
||||
|
||||
fn deserialize_field_visitor(
|
||||
@@ -1066,7 +983,7 @@ fn deserialize_struct_visitor(
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
fields: &[(ast::StructField, attr::FieldAttrs)],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
||||
let field_exprs = fields.iter()
|
||||
@@ -1094,7 +1011,7 @@ fn deserialize_struct_visitor(
|
||||
let fields_expr = builder.expr().ref_().slice()
|
||||
.with_exprs(
|
||||
fields.iter()
|
||||
.map(|&(field, _)| {
|
||||
.map(|&(ref field, _)| {
|
||||
match field.ident {
|
||||
Some(name) => builder.expr().str(name),
|
||||
None => {
|
||||
@@ -1118,7 +1035,7 @@ fn deserialize_map(
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
fields: &[(ast::StructField, attr::FieldAttrs)],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
// Create the field names for the fields.
|
||||
@@ -1140,7 +1057,7 @@ fn deserialize_map(
|
||||
// Match arms to extract a value for a field.
|
||||
let value_arms = fields_attrs_names.iter()
|
||||
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||
.map(|&(field, ref attrs, name)| {
|
||||
.map(|&(ref field, ref attrs, name)| {
|
||||
let deser_name = attrs.name().deserialize_name();
|
||||
let name_str = builder.expr().lit().str(deser_name);
|
||||
|
||||
@@ -1248,21 +1165,6 @@ fn deserialize_map(
|
||||
}))
|
||||
}
|
||||
|
||||
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(
|
||||
@@ -1319,9 +1221,16 @@ fn expr_is_missing(
|
||||
cx: &ExtCtxt,
|
||||
attrs: &attr::FieldAttrs,
|
||||
) -> P<ast::Expr> {
|
||||
if let Some(expr) = attrs.default_expr_if_missing() {
|
||||
return expr.clone();
|
||||
match *attrs.default() {
|
||||
attr::FieldDefault::Default => {
|
||||
return quote_expr!(cx, ::std::default::Default::default());
|
||||
}
|
||||
attr::FieldDefault::Path(ref path) => {
|
||||
return quote_expr!(cx, $path());
|
||||
}
|
||||
attr::FieldDefault::None => { /* below */ }
|
||||
}
|
||||
|
||||
let name = attrs.name().deserialize_name_expr();
|
||||
match attrs.deserialize_with() {
|
||||
None => {
|
||||
|
||||
@@ -22,6 +22,11 @@ extern crate syntax;
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
extern crate rustc_plugin;
|
||||
|
||||
#[cfg(feature = "with-syntex")]
|
||||
use std::io;
|
||||
#[cfg(feature = "with-syntex")]
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
use syntax::feature_gate::AttributeType;
|
||||
|
||||
@@ -31,6 +36,16 @@ include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
include!("lib.rs.in");
|
||||
|
||||
#[cfg(feature = "with-syntex")]
|
||||
pub fn expand<S, D>(src: S, dst: D) -> io::Result<()>
|
||||
where S: AsRef<Path>,
|
||||
D: AsRef<Path>,
|
||||
{
|
||||
let mut registry = syntex::Registry::new();
|
||||
register(&mut registry);
|
||||
registry.expand("", src.as_ref(), dst.as_ref())
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-syntex")]
|
||||
pub fn register(reg: &mut syntex::Registry) {
|
||||
use syntax::{ast, fold};
|
||||
|
||||
+206
-102
@@ -60,7 +60,9 @@ fn serialize_item(
|
||||
}
|
||||
};
|
||||
|
||||
let impl_generics = build_impl_generics(cx, builder, item, generics);
|
||||
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||
|
||||
let impl_generics = try!(build_impl_generics(cx, builder, item, generics, &container_attrs));
|
||||
|
||||
let ty = builder.ty().path()
|
||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||
@@ -70,7 +72,8 @@ fn serialize_item(
|
||||
&builder,
|
||||
&item,
|
||||
&impl_generics,
|
||||
ty.clone()));
|
||||
ty.clone(),
|
||||
&container_attrs));
|
||||
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
@@ -99,32 +102,36 @@ fn build_impl_generics(
|
||||
builder: &aster::AstBuilder,
|
||||
item: &Item,
|
||||
generics: &ast::Generics,
|
||||
) -> ast::Generics {
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<ast::Generics, Error> {
|
||||
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
|
||||
|
||||
let generics = try!(bound::with_where_predicates_from_fields(
|
||||
cx, builder, item, &generics,
|
||||
|attrs| attrs.ser_bound()));
|
||||
|
||||
match container_attrs.ser_bound() {
|
||||
Some(predicates) => {
|
||||
let generics = bound::with_where_predicates(builder, &generics, predicates);
|
||||
Ok(generics)
|
||||
}
|
||||
None => {
|
||||
let generics = try!(bound::with_bound(cx, builder, item, &generics,
|
||||
needs_serialize_bound,
|
||||
&builder.path().ids(&["_serde", "ser", "Serialize"]).build()));
|
||||
Ok(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
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
// serialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(attrs: &attr::FieldAttrs) -> bool {
|
||||
!attrs.skip_serializing_field()
|
||||
&& attrs.serialize_with().is_none()
|
||||
&& attrs.ser_bound().is_none()
|
||||
}
|
||||
|
||||
fn serialize_body(
|
||||
@@ -133,9 +140,8 @@ fn serialize_body(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||
|
||||
match item.node {
|
||||
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||
serialize_item_struct(
|
||||
@@ -145,7 +151,7 @@ fn serialize_body(
|
||||
ty,
|
||||
item.span,
|
||||
variant_data,
|
||||
&container_attrs,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
@@ -156,7 +162,7 @@ fn serialize_body(
|
||||
impl_generics,
|
||||
ty,
|
||||
enum_def,
|
||||
&container_attrs,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
@@ -185,6 +191,10 @@ fn serialize_item_struct(
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
serialize_newtype_struct(
|
||||
cx,
|
||||
&builder,
|
||||
impl_generics,
|
||||
ty,
|
||||
&fields[0],
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
@@ -198,7 +208,7 @@ fn serialize_item_struct(
|
||||
&builder,
|
||||
impl_generics,
|
||||
ty,
|
||||
fields.len(),
|
||||
fields,
|
||||
container_attrs,
|
||||
)
|
||||
}
|
||||
@@ -232,12 +242,24 @@ fn serialize_unit_struct(
|
||||
|
||||
fn serialize_newtype_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
impl_generics: &ast::Generics,
|
||||
container_ty: P<ast::Ty>,
|
||||
field: &ast::StructField,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let type_name = container_attrs.name().serialize_name_expr();
|
||||
|
||||
let attrs = try!(attr::FieldAttrs::from_field(cx, 0, field));
|
||||
|
||||
let mut field_expr = quote_expr!(cx, &self.0);
|
||||
if let Some(path) = attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(cx, builder,
|
||||
&container_ty, impl_generics, &field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
Ok(quote_expr!(cx,
|
||||
_serializer.serialize_newtype_struct($type_name, &self.0)
|
||||
_serializer.serialize_newtype_struct($type_name, $field_expr)
|
||||
))
|
||||
}
|
||||
|
||||
@@ -246,10 +268,10 @@ fn serialize_tuple_struct(
|
||||
builder: &aster::AstBuilder,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
fields: usize,
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||
let (visitor_struct, visitor_impl) = try!(serialize_tuple_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
ty.clone(),
|
||||
@@ -260,7 +282,8 @@ fn serialize_tuple_struct(
|
||||
builder.id("serialize_tuple_struct_elt"),
|
||||
fields,
|
||||
impl_generics,
|
||||
);
|
||||
false,
|
||||
));
|
||||
|
||||
let type_name = container_attrs.name().serialize_name_expr();
|
||||
|
||||
@@ -362,12 +385,8 @@ fn serialize_variant(
|
||||
|
||||
match variant.node.data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
let pat = builder.pat().path()
|
||||
.id(type_ident).id(variant_ident)
|
||||
.build();
|
||||
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => {
|
||||
$type_ident::$variant_ident => {
|
||||
_serde::ser::Serializer::serialize_unit_variant(
|
||||
_serializer,
|
||||
$type_name,
|
||||
@@ -378,23 +397,19 @@ fn serialize_variant(
|
||||
))
|
||||
},
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
let field = builder.id("__simple_value");
|
||||
let field = builder.pat().ref_id(field);
|
||||
let pat = builder.pat().enum_()
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
.with_pats(Some(field).into_iter())
|
||||
.build();
|
||||
let expr = try!(serialize_newtype_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_name,
|
||||
variant_index,
|
||||
variant_name,
|
||||
ty,
|
||||
generics,
|
||||
&fields[0],
|
||||
));
|
||||
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => {
|
||||
_serde::ser::Serializer::serialize_newtype_variant(
|
||||
_serializer,
|
||||
$type_name,
|
||||
$variant_index,
|
||||
$variant_name,
|
||||
__simple_value,
|
||||
)
|
||||
}
|
||||
$type_ident::$variant_ident(ref __simple_value) => { $expr }
|
||||
))
|
||||
},
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
@@ -410,7 +425,7 @@ fn serialize_variant(
|
||||
)
|
||||
.build();
|
||||
|
||||
let expr = serialize_tuple_variant(
|
||||
let expr = try!(serialize_tuple_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_name,
|
||||
@@ -420,7 +435,7 @@ fn serialize_variant(
|
||||
ty,
|
||||
fields,
|
||||
field_names,
|
||||
);
|
||||
));
|
||||
|
||||
Ok(quote_arm!(cx,
|
||||
$pat => { $expr }
|
||||
@@ -468,6 +483,35 @@ fn serialize_variant(
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_name: P<ast::Expr>,
|
||||
variant_index: usize,
|
||||
variant_name: P<ast::Expr>,
|
||||
container_ty: P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
field: &ast::StructField,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let attrs = try!(attr::FieldAttrs::from_field(cx, 0, field));
|
||||
|
||||
let mut field_expr = quote_expr!(cx, __simple_value);
|
||||
if let Some(path) = attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(cx, builder,
|
||||
&container_ty, generics, &field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
Ok(quote_expr!(cx,
|
||||
_serde::ser::Serializer::serialize_newtype_variant(
|
||||
_serializer,
|
||||
$type_name,
|
||||
$variant_index,
|
||||
$variant_name,
|
||||
$field_expr,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
@@ -478,7 +522,7 @@ fn serialize_tuple_variant(
|
||||
structure_ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
field_names: Vec<Ident>,
|
||||
) -> P<ast::Expr> {
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let variant_ty = builder.ty().tuple()
|
||||
.with_tys(
|
||||
fields.iter().map(|field| {
|
||||
@@ -490,15 +534,16 @@ fn serialize_tuple_variant(
|
||||
)
|
||||
.build();
|
||||
|
||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||
let (visitor_struct, visitor_impl) = try!(serialize_tuple_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
variant_ty,
|
||||
builder.id("serialize_tuple_variant_elt"),
|
||||
fields.len(),
|
||||
fields,
|
||||
generics,
|
||||
);
|
||||
true,
|
||||
));
|
||||
|
||||
let value_expr = builder.expr().tuple()
|
||||
.with_exprs(
|
||||
@@ -508,7 +553,7 @@ fn serialize_tuple_variant(
|
||||
)
|
||||
.build();
|
||||
|
||||
quote_expr!(cx, {
|
||||
Ok(quote_expr!(cx, {
|
||||
$visitor_struct
|
||||
$visitor_impl
|
||||
_serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, Visitor {
|
||||
@@ -516,7 +561,7 @@ fn serialize_tuple_variant(
|
||||
state: 0,
|
||||
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
@@ -614,20 +659,33 @@ fn serialize_tuple_struct_visitor(
|
||||
structure_ty: P<ast::Ty>,
|
||||
variant_ty: P<ast::Ty>,
|
||||
serializer_method: ast::Ident,
|
||||
fields: usize,
|
||||
generics: &ast::Generics
|
||||
) -> (P<ast::Item>, P<ast::Item>) {
|
||||
let arms: Vec<ast::Arm> = (0 .. fields)
|
||||
.map(|i| {
|
||||
let expr = builder.expr().method_call(serializer_method)
|
||||
.id("_serializer")
|
||||
.arg().ref_().tup_field(i).field("value").self_()
|
||||
.build();
|
||||
fields: &[ast::StructField],
|
||||
generics: &ast::Generics,
|
||||
is_enum: bool,
|
||||
) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
|
||||
let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
|
||||
|
||||
let arms: Vec<_> = fields_with_attrs.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(ref field, ref attrs))| {
|
||||
let mut field_expr = builder.expr().tup_field(i).field("value").self_();
|
||||
if !is_enum {
|
||||
field_expr = quote_expr!(cx, &$field_expr);
|
||||
}
|
||||
|
||||
let continue_if_skip = attrs.skip_serializing_if()
|
||||
.map(|path| quote_stmt!(cx, if $path($field_expr) { continue }));
|
||||
|
||||
if let Some(path) = attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(cx, builder,
|
||||
&structure_ty, generics, &field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_arm!(cx,
|
||||
$i => {
|
||||
self.state += 1;
|
||||
Ok(Some(try!($expr)))
|
||||
$continue_if_skip
|
||||
Ok(Some(try!(_serializer.$serializer_method($field_expr))))
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -644,7 +702,9 @@ fn serialize_tuple_struct_visitor(
|
||||
.strip_bounds()
|
||||
.build();
|
||||
|
||||
(
|
||||
let nfields = fields.len();
|
||||
|
||||
Ok((
|
||||
quote_item!(cx,
|
||||
struct Visitor $visitor_impl_generics $where_clause {
|
||||
state: usize,
|
||||
@@ -669,11 +729,11 @@ fn serialize_tuple_struct_visitor(
|
||||
|
||||
#[inline]
|
||||
fn len(&self) -> Option<usize> {
|
||||
Some($fields)
|
||||
Some($nfields)
|
||||
}
|
||||
}
|
||||
).unwrap(),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_struct_visitor(
|
||||
@@ -686,28 +746,27 @@ fn serialize_struct_visitor(
|
||||
generics: &ast::Generics,
|
||||
is_enum: bool,
|
||||
) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
|
||||
let field_attrs = try!(
|
||||
attr::get_struct_field_attrs(cx, &structure_ty, generics, fields, is_enum)
|
||||
);
|
||||
let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
|
||||
|
||||
let arms: Vec<ast::Arm> = fields.iter().zip(field_attrs.iter())
|
||||
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field())
|
||||
let arms: Vec<ast::Arm> = fields_with_attrs.iter()
|
||||
.filter(|&&(_, ref attrs)| !attrs.skip_serializing_field())
|
||||
.enumerate()
|
||||
.map(|(i, (ref field, ref field_attr))| {
|
||||
let name = field.ident.expect("struct has unnamed field");
|
||||
.map(|(i, &(ref field, ref attrs))| {
|
||||
let ident = field.ident.expect("struct has unnamed field");
|
||||
let mut field_expr = quote_expr!(cx, self.value.$ident);
|
||||
if !is_enum {
|
||||
field_expr = quote_expr!(cx, &$field_expr);
|
||||
}
|
||||
|
||||
let key_expr = field_attr.name().serialize_name_expr();
|
||||
let key_expr = attrs.name().serialize_name_expr();
|
||||
|
||||
let stmt = if let Some(expr) = field_attr.skip_serializing_field_if() {
|
||||
Some(quote_stmt!(cx, if $expr { continue; }))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let continue_if_skip = attrs.skip_serializing_if()
|
||||
.map(|path| quote_stmt!(cx, if $path($field_expr) { continue }));
|
||||
|
||||
let field_expr = match field_attr.serialize_with() {
|
||||
Some(expr) => expr.clone(),
|
||||
None => quote_expr!(cx, &self.value.$name),
|
||||
};
|
||||
if let Some(path) = attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(cx, builder,
|
||||
&structure_ty, generics, &field.ty, path, field_expr)
|
||||
}
|
||||
|
||||
let expr = quote_expr!(cx,
|
||||
_serializer.$serializer_method($key_expr, $field_expr)
|
||||
@@ -716,7 +775,7 @@ fn serialize_struct_visitor(
|
||||
quote_arm!(cx,
|
||||
$i => {
|
||||
self.state += 1;
|
||||
$stmt
|
||||
$continue_if_skip
|
||||
return Ok(Some(try!($expr)));
|
||||
}
|
||||
)
|
||||
@@ -734,16 +793,18 @@ fn serialize_struct_visitor(
|
||||
.strip_bounds()
|
||||
.build();
|
||||
|
||||
let len = field_attrs.iter()
|
||||
.filter(|field_attr| !field_attr.skip_serializing_field())
|
||||
.map(|field_attr| {
|
||||
match field_attr.skip_serializing_field_if() {
|
||||
Some(expr) => {
|
||||
quote_expr!(cx, if $expr { 0 } else { 1 })
|
||||
}
|
||||
None => {
|
||||
quote_expr!(cx, 1)
|
||||
}
|
||||
let len = fields_with_attrs.iter()
|
||||
.filter(|&&(_, ref attrs)| !attrs.skip_serializing_field())
|
||||
.map(|&(ref field, ref attrs)| {
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
let mut field_expr = quote_expr!(cx, self.value.$ident);
|
||||
if !is_enum {
|
||||
field_expr = quote_expr!(cx, &$field_expr);
|
||||
}
|
||||
|
||||
match attrs.skip_serializing_if() {
|
||||
Some(path) => quote_expr!(cx, if $path($field_expr) { 0 } else { 1 }),
|
||||
None => quote_expr!(cx, 1),
|
||||
}
|
||||
})
|
||||
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
|
||||
@@ -782,3 +843,46 @@ fn serialize_struct_visitor(
|
||||
).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
fn wrap_serialize_with(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
field_ty: &P<ast::Ty>,
|
||||
path: &ast::Path,
|
||||
value: P<ast::Expr>,
|
||||
) -> P<ast::Expr> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let wrapper_generics = builder.from_generics(generics.clone())
|
||||
.add_lifetime_bound("'__a")
|
||||
.lifetime_name("'__a")
|
||||
.build();
|
||||
|
||||
let wrapper_ty = builder.path()
|
||||
.segment("__SerializeWith")
|
||||
.with_generics(wrapper_generics.clone())
|
||||
.build()
|
||||
.build();
|
||||
|
||||
quote_expr!(cx, {
|
||||
struct __SerializeWith $wrapper_generics $where_clause {
|
||||
value: &'__a $field_ty,
|
||||
phantom: ::std::marker::PhantomData<$container_ty>,
|
||||
}
|
||||
|
||||
impl $wrapper_generics _serde::ser::Serialize for $wrapper_ty $where_clause {
|
||||
fn serialize<__S>(&self, __s: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
$path(self.value, __s)
|
||||
}
|
||||
}
|
||||
|
||||
__SerializeWith {
|
||||
value: $value,
|
||||
phantom: ::std::marker::PhantomData::<$container_ty>,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
[package]
|
||||
name = "serde_macros"
|
||||
version = "0.7.5"
|
||||
version = "0.7.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://github.com/serde-rs/serde"
|
||||
keywords = ["serde", "serialization"]
|
||||
include = ["Cargo.toml", "src/**/*.rs"]
|
||||
|
||||
[lib]
|
||||
name = "serde_macros"
|
||||
@@ -17,12 +18,13 @@ nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-tes
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
serde_codegen = { version = "^0.7.5", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
serde_codegen = { version = "^0.7.10", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
|
||||
[dev-dependencies]
|
||||
compiletest_rs = "^0.1.1"
|
||||
fnv = "1.0"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "^0.7.5", path = "../serde" }
|
||||
serde = { version = "^0.7.10", path = "../serde" }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_tests"
|
||||
version = "0.7.5"
|
||||
version = "0.7.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -14,14 +14,15 @@ build = "build.rs"
|
||||
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
|
||||
|
||||
[build-dependencies]
|
||||
syntex = { version = "^0.32.0" }
|
||||
syntex_syntax = { version = "^0.32.0" }
|
||||
syntex = { version = "^0.35.0" }
|
||||
syntex_syntax = { version = "^0.35.0" }
|
||||
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
|
||||
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "*", path = "../serde" }
|
||||
syntex = "^0.32.0"
|
||||
syntex = "^0.35.0"
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use test::Bencher;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use rustc_serialize::{Decoder, Decodable};
|
||||
use rustc_serialize::Decodable;
|
||||
use serde;
|
||||
use serde::de::{Deserializer, Deserialize};
|
||||
use serde::de::Deserialize;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ use test::Bencher;
|
||||
use std::fmt;
|
||||
use std::error;
|
||||
|
||||
use rustc_serialize::{Decoder, Decodable};
|
||||
use rustc_serialize::Decodable;
|
||||
|
||||
use serde;
|
||||
use serde::de::{Deserializer, Deserialize};
|
||||
use serde::de::Deserialize;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@ fn main() {
|
||||
] {
|
||||
let src = Path::new(src);
|
||||
let dst = Path::new(&out_dir).join(dst);
|
||||
|
||||
let mut registry = syntex::Registry::new();
|
||||
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
serde_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,14 @@ macro_rules! hashset {
|
||||
$(set.insert($value);)+
|
||||
set
|
||||
}
|
||||
};
|
||||
($hasher:ident @ $($value:expr),+) => {
|
||||
{
|
||||
use std::hash::BuildHasherDefault;
|
||||
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||
$(set.insert($value);)+
|
||||
set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,5 +83,13 @@ macro_rules! hashmap {
|
||||
$(map.insert($key, $value);)+
|
||||
map
|
||||
}
|
||||
};
|
||||
($hasher:ident @ $($key:expr => $value:expr),+) => {
|
||||
{
|
||||
use std::hash::BuildHasherDefault;
|
||||
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||
$(map.insert($key, $value);)+
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,8 @@ enum RenameEnumSerializeDeserialize<A> {
|
||||
#[serde(rename(serialize="dick_grayson", deserialize="jason_todd"))]
|
||||
Robin {
|
||||
a: i8,
|
||||
#[serde(rename(serialize="c", deserialize="d"))]
|
||||
#[serde(rename(serialize="c"))]
|
||||
#[serde(rename(deserialize="d"))]
|
||||
b: A,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::net;
|
||||
use std::path::PathBuf;
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::de::Deserializer;
|
||||
extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
|
||||
use token::{
|
||||
Error,
|
||||
@@ -287,6 +287,18 @@ declare_tests! {
|
||||
Token::TupleStructStart("Anything", Some(0)),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
hashset![FnvHasher @ 1, 2, 3] => vec![
|
||||
Token::SeqStart(Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::I32(3),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_vec {
|
||||
Vec::<isize>::new() => vec![
|
||||
@@ -535,6 +547,17 @@ declare_tests! {
|
||||
Token::StructStart("Anything", Some(0)),
|
||||
Token::MapEnd,
|
||||
],
|
||||
hashmap![FnvHasher @ 1 => 2, 3 => 4] => vec![
|
||||
Token::MapStart(Some(2)),
|
||||
Token::MapSep,
|
||||
Token::I32(1),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::I32(3),
|
||||
Token::I32(4),
|
||||
Token::MapEnd,
|
||||
],
|
||||
}
|
||||
test_struct {
|
||||
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// These just test that serde_codegen is able to produce code that compiles
|
||||
// successfully when there are a variety of generics involved.
|
||||
// successfully when there are a variety of generics and non-(de)serializable
|
||||
// types involved.
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::ser::{Serialize, Serializer};
|
||||
@@ -10,16 +11,16 @@ 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,
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
x: X,
|
||||
}
|
||||
|
||||
#[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,
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
x: X,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -40,17 +41,94 @@ struct NoBounds<T> {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EnumWith<T> {
|
||||
A(
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i32),
|
||||
B {
|
||||
Unit,
|
||||
Newtype(
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
X),
|
||||
Tuple(
|
||||
T,
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
X),
|
||||
Struct {
|
||||
t: T,
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i: i32 },
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
x: X },
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a {
|
||||
t: T,
|
||||
rrrt: &'a &'b &'c T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Newtype(
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
X
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Tuple<T>(
|
||||
T,
|
||||
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
|
||||
X,
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum TreeNode<D> {
|
||||
Split {
|
||||
left: Box<TreeNode<D>>,
|
||||
right: Box<TreeNode<D>>,
|
||||
},
|
||||
Leaf {
|
||||
data: D,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ListNode<D> {
|
||||
data: D,
|
||||
next: Box<ListNode<D>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound="D: SerializeWith + DeserializeWith")]
|
||||
struct WithTraits1<D, E> {
|
||||
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||
deserialize_with="DeserializeWith::deserialize_with")]
|
||||
d: D,
|
||||
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||
deserialize_with="DeserializeWith::deserialize_with",
|
||||
bound="E: SerializeWith + DeserializeWith")]
|
||||
e: E,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound(serialize="D: SerializeWith",
|
||||
deserialize="D: DeserializeWith"))]
|
||||
struct WithTraits2<D, E> {
|
||||
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||
deserialize_with="DeserializeWith::deserialize_with")]
|
||||
d: D,
|
||||
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||
bound(serialize="E: SerializeWith"))]
|
||||
#[serde(deserialize_with="DeserializeWith::deserialize_with",
|
||||
bound(deserialize="E: DeserializeWith"))]
|
||||
e: E,
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn ser_i32<S: Serializer>(_: &i32, _: &mut S) -> Result<(), S::Error> { panic!() }
|
||||
trait SerializeWith {
|
||||
fn serialize_with<S: Serializer>(_: &Self, _: &mut S) -> Result<(), S::Error>;
|
||||
}
|
||||
|
||||
trait DeserializeWith: Sized {
|
||||
fn deserialize_with<D: Deserializer>(_: &mut D) -> Result<Self, D::Error>;
|
||||
}
|
||||
|
||||
// Implements neither Serialize nor Deserialize
|
||||
struct X;
|
||||
fn ser_x<S: Serializer>(_: &X, _: &mut S) -> Result<(), S::Error> { panic!() }
|
||||
fn de_x<D: Deserializer>(_: &mut D) -> Result<X, D::Error> { panic!() }
|
||||
|
||||
fn de_i32<D: Deserializer>(_: &mut D) -> Result<i32, D::Error> { panic!() }
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::net;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
|
||||
use token::{self, Token};
|
||||
|
||||
extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -144,6 +147,24 @@ declare_ser_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_hashset {
|
||||
HashSet::<isize>::new() => &[
|
||||
Token::SeqStart(Some(0)),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
hashset![1] => &[
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
hashset![FnvHasher @ 1] => &[
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_tuple {
|
||||
(1,) => &[
|
||||
Token::TupleStart(1),
|
||||
@@ -204,6 +225,26 @@ declare_ser_tests! {
|
||||
Token::MapEnd,
|
||||
],
|
||||
}
|
||||
test_hashmap {
|
||||
HashMap::<isize, isize>::new() => &[
|
||||
Token::MapStart(Some(0)),
|
||||
Token::MapEnd,
|
||||
],
|
||||
hashmap![1 => 2] => &[
|
||||
Token::MapStart(Some(1)),
|
||||
Token::MapSep,
|
||||
Token::I32(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
hashmap![FnvHasher @ 1 => 2] => &[
|
||||
Token::MapStart(Some(1)),
|
||||
Token::MapSep,
|
||||
Token::I32(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
}
|
||||
test_unit_struct {
|
||||
UnitStruct => &[Token::UnitStruct("UnitStruct")],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user