Compare commits

...

42 Commits

Author SHA1 Message Date
Homu b5c0406afe Auto merge of #349 - oli-obk:undo, r=oli-obk
undo the breaking change introduced in 0.7.6

I should probably yank 0.7.6, too

cc @alexcrichton this should unbreak your setup, sorry about that.
2016-06-01 20:01:53 +09:00
Oliver Schneider 96cd910c92 undo the breaking change introduced in 0.7.6 2016-06-01 11:08:59 +02:00
Homu e0bd57d63c Auto merge of #347 - erickt:master, r=erickt
Add "include" to Cargo.toml files

This filters out junk files from the crates.

Closes #331.
2016-05-30 23:23:57 +09:00
Erick Tryzelaar 7c784f592e Add a changelog 2016-05-30 07:23:18 -07:00
Erick Tryzelaar 2c69ccdca4 Add the build script to the Cargo include section 2016-05-30 07:23:09 -07:00
Erick Tryzelaar 66eddd4d9b Add "include" to Cargo.toml files
This filters out junk files from the crates.

Closes #331.
2016-05-30 07:00:13 -07:00
Homu 1485f0a448 Auto merge of #346 - serde-rs:rustup, r=erickt
Rustup too rustc 1.11.0-nightly (7746a334d 2016-05-28)

cc @erickt
2016-05-30 22:45:47 +09:00
Manish Goregaokar 379c9e7148 Rustup too rustc 1.11.0-nightly (7746a334d 2016-05-28) 2016-05-30 14:01:57 +05:30
Homu 6c2af4da7a Auto merge of #343 - pyfisch:patch-1, r=oli-obk
Better documentation for de::Error::invalid_length

Closes #342
2016-05-24 20:32:57 +09:00
Pyfisch 2ff7d003ee Better documentation for de::Error::invalid_length
Closes #342
2016-05-24 13:07:26 +02:00
David Tolnay ea182e2561 Merge pull request #335 from dtolnay/tuples
Support (de)serialize_with in tuples
2016-05-23 13:33:58 -07:00
David Tolnay 938f42faf6 Support (de)serialize_with in tuples 2016-05-19 10:53:38 -07:00
Homu cc115ca43a Auto merge of #338 - dtolnay:refs, r=oli-obk
Strip more references

Fixes #337.
2016-05-20 02:45:31 +09:00
David Tolnay f1b4072444 Strip more references 2016-05-18 23:48:56 -07:00
Homu 16d3e96b77 Auto merge of #334 - dtolnay:dupl, r=oli-obk
Reduce code duplication in Deserialize generator

This combines `deserialize_newtype_struct`, `deserialize_tuple_struct`, and `deserialize_tuple_variant` into a single method `deserialize_tuple`, as well as `deserialize_struct` and `deserialize_struct_variant` into a single method `deserialize_struct`. No behavior changes.
2016-05-16 19:41:59 +09:00
David Tolnay 7d2423e856 Reduce code duplication in Deserialize generator
This combines deserialize_newtype_struct, deserialize_tuple_struct,
and deserialize_tuple_variant into a single method deserialize_tuple,
as well as deserialize_struct and deserialize_struct_variant into a
single method deserialize_struct. No behavior changes.
2016-05-15 13:32:54 -07:00
David Tolnay 9865ec23c7 Merge pull request #322 from dtolnay/unused
Remove unused imports and needless borrows
2016-05-13 11:23:15 -07:00
David Tolnay 76a321db5c Simplify redundant closure 2016-05-13 10:53:03 -07:00
David Tolnay 004dcaec3b Remove unused imports and needless borrows 2016-05-13 10:47:09 -07:00
Homu 74eb2f52b8 Auto merge of #316 - cmr:no_std, r=oli-obk
Enable use in no_std environments

Re-opening of #302 after bust merge.
2016-05-13 17:13:08 +09:00
Corey Richardson 9b7317fbb1 Address nits 2016-05-13 11:17:17 +10:00
Erick Tryzelaar 41142d41ee Merge pull request #319 from dtolnay/release
Release 0.7.5
2016-05-12 09:30:41 -07:00
Homu fd328c2f2a Auto merge of #320 - dtolnay:syntexv, r=oli-obk
Do not depend on multiple syntex versions

serde_codegen has syntex 0.32 under dependencies, but syntex 0.31 under build-dependencies...
2016-05-12 04:05:47 +09:00
David Tolnay 3ad276944a Do not depend on multiple syntex versions 2016-05-11 09:52:28 -07:00
David Tolnay bb20796e9d Bump version numbers in serde-syntex-example 2016-05-11 09:46:16 -07:00
David Tolnay 709ac64dfc Release 0.7.5 2016-05-11 09:36:30 -07:00
Homu a9a4b2d8e2 Auto merge of #293 - dtolnay:duplicate, r=oli-obk
feat(codegen): Detect repeated struct field when deserializing

Addresses #59. Let me know whether you think we need an escape hatch to opt out of this check.
2016-05-11 19:44:34 +09:00
Oliver Schneider 7374ac499d Merge pull request #311 from dtolnay/deserialize_with
Field with deserialize_with should not implement Deserialize
2016-05-11 11:48:19 +02:00
Oliver Schneider 6596f77e91 Merge pull request #315 from dtolnay/underscore
Prefix type parameters and lifetimes with double underscore
2016-05-11 11:06:25 +02:00
David Tolnay eeb4efc19c feat(codegen): Detect repeated struct field when deserializing 2016-05-10 09:52:51 -07:00
David Tolnay 76b70455ec Field with deserialize_with should not implement Deserialize 2016-05-10 09:50:32 -07:00
David Tolnay f43c8a6267 Prefix type parameters and lifetimes with double underscore 2016-05-10 09:12:38 -07:00
Corey Richardson ae806af644 Enable use in no_std environments
These changes are fairly invasive to imports and uses of non-libcore types,
but allow for some or none of the freestanding crates (core, rustc_unicode,
alloc, collections) to be supported by serde.
2016-05-10 10:23:41 +10:00
Homu 7aa0b6ce27 Auto merge of #314 - dtolnay:revert, r=erickt
Revert "Enable use in no_std environments"

This commit failed to build even before it was merged. See #313.
2016-05-09 12:47:09 +09:00
David Tolnay efdbf5795f Fix version in serde/Cargo.toml 2016-05-08 20:43:46 -07:00
David Tolnay 55355b6680 Revert "Enable use in no_std environments"
This reverts commit 9c0140968d.
2016-05-08 20:30:21 -07:00
Erick Tryzelaar f8a91e5176 Merge pull request #302 from cmr/no_std
Enable use in no_std environments
2016-05-08 19:24:48 -07:00
Erick Tryzelaar aa0cd9b3dc Merge pull request #308 from dtolnay/inference
Reduce dependence on type inference
2016-05-08 19:21:45 -07:00
Erick Tryzelaar 1f82cd6e3d Merge pull request #310 from dtolnay/withdoc
Clarify serialize_with and deserialize_with documentation
2016-05-08 19:20:12 -07:00
David Tolnay 3caac4e6f3 Clarify serialize_with and deserialize_with documentation 2016-05-08 10:52:23 -07:00
David Tolnay f4414bfc14 Reduce dependence on type inference 2016-05-07 15:25:13 -07:00
Corey Richardson 9c0140968d Enable use in no_std environments
These changes are fairly invasive to imports and uses of non-libcore types,
but allow for some or none of the freestanding crates (core, rustc_unicode,
alloc, collections) to be supported by serde.
2016-05-04 01:26:43 +10:00
29 changed files with 1292 additions and 798 deletions
+4
View File
@@ -18,6 +18,10 @@ script:
- (cd serde && travis-cargo build) - (cd serde && travis-cargo build)
- (cd serde && travis-cargo test) - (cd serde && travis-cargo test)
- (cd serde && travis-cargo --only nightly test -- --features nightly-testing) - (cd serde && travis-cargo --only nightly test -- --features nightly-testing)
- (cd serde && travis-cargo --skip 1.5.0 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 test)
- (cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing) - (cd serde_tests && travis-cargo --only nightly test -- --features nightly-testing)
- (cd serde_macros && travis-cargo --only nightly test -- --features nightly-testing) - (cd serde_macros && travis-cargo --only nightly test -- --features nightly-testing)
+10
View File
@@ -0,0 +1,10 @@
## 0.7.6
NOTES:
* Syncs `serde_codegen` and `serde_macros` with rustc 1.10.0-nightly (7bddce693 2016-05-27).
FEATURES:
* `#[serde(serialize_with=..., deserialize_with=...)]` now supports tuples. #335
* Serde now can be used in `#[no_std]` environments. #316
+26 -12
View File
@@ -705,18 +705,32 @@ Variant Annotations:
Field Annotations: Field Annotations:
| Annotation | Function | | Annotation | Function |
| ---------- | -------- | | ---------- | -------- |
| `#[serde(rename="name")]` | Serialize and deserialize this field with the given name | | `#[serde(rename="name")]` | Serialize and deserialize this field with the given name |
| `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name | | `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name |
| `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name | | `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name |
| `#[serde(default)]` | If the value is not specified, use the `Default::default()` | | `#[serde(default)]` | If the value is not specified, use the `Default::default()` |
| `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value | | `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value |
| `#[serde(skip_serializing)]` | Do not serialize this value | | `#[serde(skip_serializing)]` | Do not serialize this value |
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing 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(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<T, S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value | | `#[serde(serialize_with="$path")]` | Call a function `fn<S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value of type `T` |
| `#[serde(deserialize_with="$path")]` | Call a function `fn<T, D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value | | `#[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` |
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 Upgrading from Serde 0.6
======================== ========================
+5 -5
View File
@@ -9,10 +9,10 @@ default = ["serde_codegen"]
nightly = ["serde_macros"] nightly = ["serde_macros"]
[build-dependencies] [build-dependencies]
serde_codegen = { version = "^0.6.4", optional = true } serde_codegen = { version = "^0.7.5", optional = true }
syntex = "^0.22.0" syntex = "^0.32.0"
[dependencies] [dependencies]
serde = "^0.6.1" serde = "^0.7.5"
serde_json = "^0.6.0" serde_json = "^0.7.0"
serde_macros = { version = "^0.6.1", optional = true } serde_macros = { version = "^0.7.5", optional = true }
+8 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "0.7.4" version = "0.7.7"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
@@ -8,10 +8,16 @@ repository = "https://github.com/serde-rs/serde"
documentation = "https://serde-rs.github.io/serde/serde/" documentation = "https://serde-rs.github.io/serde/serde/"
readme = "../README.md" readme = "../README.md"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[features] [features]
default = ["std"]
std = []
nightly = [] nightly = []
nightly-testing = ["clippy", "nightly"] alloc = ["nightly"]
collections = ["alloc"]
nightly-testing = ["clippy", "nightly", "std"]
[dependencies] [dependencies]
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
+159 -135
View File
@@ -1,11 +1,15 @@
//! Helper module to enable serializing bytes more efficiently //! Helper module to enable serializing bytes more efficiently
use std::ops; use core::{ops, fmt, char, iter, slice};
use std::fmt; use core::fmt::Write;
use std::ascii;
use ser; 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> { impl<'a> fmt::Debug for Bytes<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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> { impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
fn from(bytes: &'a Vec<u8>) -> Self { fn from(bytes: &'a Vec<u8>) -> Self {
Bytes { 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. #[cfg(any(feature = "std", feature = "collections"))]
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)] mod bytebuf {
pub struct ByteBuf { use core::ops;
bytes: Vec<u8>, use core::fmt;
} use core::fmt::Write;
impl ByteBuf { use ser;
/// Construct a new, empty `ByteBuf`. use de;
pub fn new() -> Self {
ByteBuf { #[cfg(feature = "collections")]
bytes: Vec::new(), 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. impl fmt::Debug for ByteBuf {
pub fn with_capacity(cap: usize) -> Self { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ByteBuf { try!(f.write_str("b\""));
bytes: Vec::with_capacity(cap) for c in super::escape_bytestring(self.bytes.as_ref()) {
try!(f.write_char(c));
}
f.write_char('"')
} }
} }
}
impl fmt::Debug for ByteBuf { impl Into<Vec<u8>> for ByteBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn into(self) -> Vec<u8> {
write!(f, "b\"{}\"", escape_bytestring(self.bytes.as_ref())) self.bytes
}
}
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 AsRef<Vec<u8>> for ByteBuf { impl From<Vec<u8>> for ByteBuf {
fn as_ref(&self) -> &Vec<u8> { fn from(bytes: Vec<u8>) -> Self {
&self.bytes ByteBuf {
} bytes: 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(),
})
} }
#[inline] impl AsRef<Vec<u8>> for ByteBuf {
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<ByteBuf, V::Error> fn as_ref(&self) -> &Vec<u8> {
where V: de::SeqVisitor, &self.bytes
{ }
let (len, _) = visitor.size_hint(); }
let mut values = Vec::with_capacity(len);
while let Some(value) = try!(visitor.visit()) { impl AsRef<[u8]> for ByteBuf {
values.push(value); 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 { while let Some(value) = try!(visitor.visit()) {
bytes: values, 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] impl de::Deserialize for ByteBuf {
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<ByteBuf, E> #[inline]
where E: de::Error, fn deserialize<D>(deserializer: &mut D) -> Result<ByteBuf, D::Error>
{ where D: de::Deserializer
self.visit_byte_buf(v.to_vec()) {
} deserializer.deserialize_bytes(ByteBufVisitor)
}
#[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)
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
fn escape_bytestring(bytes: &[u8]) -> String { #[inline]
let mut result = String::new(); fn escape_bytestring<'a>(bytes: &'a [u8]) -> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
for &b in bytes { fn f(b: &u8) -> char::EscapeDefault {
for esc in ascii::escape_default(b) { char::from_u32(*b as u32).unwrap().escape_default()
result.push(esc as char);
}
} }
result bytes.iter().flat_map(f as fn(&u8) -> char::EscapeDefault)
} }
+5 -5
View File
@@ -13,10 +13,10 @@
// Rust 1.5 is unhappy that this private module is undocumented. // Rust 1.5 is unhappy that this private module is undocumented.
#![allow(missing_docs)] #![allow(missing_docs)]
use std::{usize, u8, u16, u32, u64}; use core::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64}; use core::{isize, i8, i16, i32, i64};
use std::{f32, f64}; use core::{f32, f64};
use std::mem::size_of; use core::mem::size_of;
/// Numbers which have upper and lower bounds /// Numbers which have upper and lower bounds
pub trait Bounded { pub trait Bounded {
@@ -274,7 +274,7 @@ macro_rules! impl_to_primitive_float_to_float {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
let n = $slf as f64; 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 { if -max_value as f64 <= n && n <= max_value as f64 {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
+80 -11
View File
@@ -1,30 +1,63 @@
//! This module contains `Deserialize` and `Visitor` implementations. //! This module contains `Deserialize` and `Visitor` implementations.
#[cfg(feature = "std")]
use std::borrow::Cow; 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, BinaryHeap,
BTreeMap, BTreeMap,
BTreeSet, BTreeSet,
LinkedList, LinkedList,
VecDeque,
Vec,
String,
};
#[cfg(feature = "std")]
use std::collections::{
HashMap, HashMap,
HashSet, HashSet,
BinaryHeap,
BTreeMap,
BTreeSet,
LinkedList,
VecDeque, VecDeque,
}; };
#[cfg(feature = "nightly")]
#[cfg(all(feature = "nightly", feature = "collections"))]
use collections::enum_set::{CLike, EnumSet}; use collections::enum_set::{CLike, EnumSet};
use std::hash::Hash; #[cfg(all(feature = "nightly", feature = "collections"))]
use std::marker::PhantomData; use collections::borrow::ToOwned;
use core::hash::Hash;
use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::net; use std::net;
#[cfg(feature = "std")]
use std::path; use std::path;
use core::str;
#[cfg(feature = "std")]
use std::rc::Rc; 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; 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")] #[cfg(feature = "nightly")]
use core::nonzero::{NonZero, Zeroable}; use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use std::num::Zero; use core::num::Zero;
use de::{ use de::{
Deserialize, Deserialize,
@@ -85,7 +118,7 @@ impl Visitor for BoolVisitor {
fn visit_str<E>(&mut self, s: &str) -> Result<bool, E> fn visit_str<E>(&mut self, s: &str) -> Result<bool, E>
where E: Error, where E: Error,
{ {
match s.trim() { match s.trim_matches(::utils::Pattern_White_Space) {
"true" => Ok(true), "true" => Ok(true),
"false" => Ok(false), "false" => Ok(false),
_ => Err(Error::invalid_type(Type::Bool)), _ => 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); impl_deserialize_num_method!(f64, visit_f64, from_f64, Type::F64);
#[inline] #[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, 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)) Err(Error::invalid_type(Type::Str))
}) })
} }
@@ -228,8 +261,10 @@ impl Deserialize for char {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
struct StringVisitor; struct StringVisitor;
#[cfg(any(feature = "std", feature = "collections"))]
impl Visitor for StringVisitor { impl Visitor for StringVisitor {
type Value = String; type Value = String;
@@ -264,6 +299,7 @@ impl Visitor for StringVisitor {
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
impl Deserialize for String { impl Deserialize for String {
fn deserialize<D>(deserializer: &mut D) -> Result<String, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<String, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -406,6 +442,7 @@ macro_rules! seq_impl {
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
seq_impl!( seq_impl!(
BinaryHeap<T>, BinaryHeap<T>,
<Deserialize, Ord>, <Deserialize, Ord>,
@@ -415,6 +452,7 @@ seq_impl!(
BinaryHeap::with_capacity(visitor.size_hint().0), BinaryHeap::with_capacity(visitor.size_hint().0),
BinaryHeap::push); BinaryHeap::push);
#[cfg(any(feature = "std", feature = "collections"))]
seq_impl!( seq_impl!(
BTreeSet<T>, BTreeSet<T>,
<Deserialize, Eq, Ord>, <Deserialize, Eq, Ord>,
@@ -424,7 +462,7 @@ seq_impl!(
BTreeSet::new(), BTreeSet::new(),
BTreeSet::insert); BTreeSet::insert);
#[cfg(feature = "nightly")] #[cfg(all(feature = "nightly", feature = "collections"))]
seq_impl!( seq_impl!(
EnumSet<T>, EnumSet<T>,
<Deserialize, CLike>, <Deserialize, CLike>,
@@ -434,6 +472,7 @@ seq_impl!(
EnumSet::new(), EnumSet::new(),
EnumSet::insert); EnumSet::insert);
#[cfg(any(feature = "std", feature = "collections"))]
seq_impl!( seq_impl!(
LinkedList<T>, LinkedList<T>,
<Deserialize>, <Deserialize>,
@@ -443,6 +482,7 @@ seq_impl!(
LinkedList::new(), LinkedList::new(),
LinkedList::push_back); LinkedList::push_back);
#[cfg(feature = "std")]
seq_impl!( seq_impl!(
HashSet<T>, HashSet<T>,
<Deserialize, Eq, Hash>, <Deserialize, Eq, Hash>,
@@ -452,6 +492,7 @@ seq_impl!(
HashSet::with_capacity(visitor.size_hint().0), HashSet::with_capacity(visitor.size_hint().0),
HashSet::insert); HashSet::insert);
#[cfg(any(feature = "std", feature = "collections"))]
seq_impl!( seq_impl!(
Vec<T>, Vec<T>,
<Deserialize>, <Deserialize>,
@@ -461,6 +502,7 @@ seq_impl!(
Vec::with_capacity(visitor.size_hint().0), Vec::with_capacity(visitor.size_hint().0),
Vec::push); Vec::push);
#[cfg(any(feature = "std", feature = "collections"))]
seq_impl!( seq_impl!(
VecDeque<T>, VecDeque<T>,
<Deserialize>, <Deserialize>,
@@ -747,6 +789,7 @@ macro_rules! map_impl {
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
map_impl!( map_impl!(
BTreeMap<K, V>, BTreeMap<K, V>,
<Deserialize, Eq, Ord>, <Deserialize, Eq, Ord>,
@@ -756,6 +799,7 @@ map_impl!(
BTreeMap::new(), BTreeMap::new(),
BTreeMap::insert); BTreeMap::insert);
#[cfg(feature = "std")]
map_impl!( map_impl!(
HashMap<K, V>, HashMap<K, V>,
<Deserialize, Eq, Hash>, <Deserialize, Eq, Hash>,
@@ -767,7 +811,7 @@ map_impl!(
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "nightly")] #[cfg(all(feature = "nightly", feature = "std"))]
impl Deserialize for net::IpAddr { impl Deserialize for net::IpAddr {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -780,6 +824,7 @@ impl Deserialize for net::IpAddr {
} }
} }
#[cfg(feature = "std")]
impl Deserialize for net::Ipv4Addr { impl Deserialize for net::Ipv4Addr {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -792,6 +837,7 @@ impl Deserialize for net::Ipv4Addr {
} }
} }
#[cfg(feature = "std")]
impl Deserialize for net::Ipv6Addr { impl Deserialize for net::Ipv6Addr {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -806,6 +852,7 @@ impl Deserialize for net::Ipv6Addr {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Deserialize for net::SocketAddr { impl Deserialize for net::SocketAddr {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -818,6 +865,7 @@ impl Deserialize for net::SocketAddr {
} }
} }
#[cfg(feature = "std")]
impl Deserialize for net::SocketAddrV4 { impl Deserialize for net::SocketAddrV4 {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -830,6 +878,7 @@ impl Deserialize for net::SocketAddrV4 {
} }
} }
#[cfg(feature = "std")]
impl Deserialize for net::SocketAddrV6 { impl Deserialize for net::SocketAddrV6 {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -844,8 +893,10 @@ impl Deserialize for net::SocketAddrV6 {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
struct PathBufVisitor; struct PathBufVisitor;
#[cfg(feature = "std")]
impl Visitor for PathBufVisitor { impl Visitor for PathBufVisitor {
type Value = path::PathBuf; type Value = path::PathBuf;
@@ -862,6 +913,7 @@ impl Visitor for PathBufVisitor {
} }
} }
#[cfg(feature = "std")]
impl Deserialize for path::PathBuf { impl Deserialize for path::PathBuf {
fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<path::PathBuf, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -872,6 +924,7 @@ impl Deserialize for path::PathBuf {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Deserialize> Deserialize for Box<T> { impl<T: Deserialize> Deserialize for Box<T> {
fn deserialize<D>(deserializer: &mut D) -> Result<Box<T>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Box<T>, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -881,6 +934,7 @@ impl<T: Deserialize> Deserialize for Box<T> {
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
impl<T: Deserialize> Deserialize for Box<[T]> { impl<T: Deserialize> Deserialize for Box<[T]> {
fn deserialize<D>(deserializer: &mut D) -> Result<Box<[T]>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Box<[T]>, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -890,6 +944,7 @@ impl<T: Deserialize> Deserialize for Box<[T]> {
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Deserialize> Deserialize for Arc<T> { impl<T: Deserialize> Deserialize for Arc<T> {
fn deserialize<D>(deserializer: &mut D) -> Result<Arc<T>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Arc<T>, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -899,6 +954,7 @@ impl<T: Deserialize> Deserialize for Arc<T> {
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Deserialize> Deserialize for Rc<T> { impl<T: Deserialize> Deserialize for Rc<T> {
fn deserialize<D>(deserializer: &mut D) -> Result<Rc<T>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Rc<T>, D::Error>
where D: Deserializer, where D: Deserializer,
@@ -908,6 +964,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, { impl<'a, T: ?Sized> Deserialize for Cow<'a, T> where T: ToOwned, T::Owned: Deserialize, {
#[inline] #[inline]
fn deserialize<D>(deserializer: &mut D) -> Result<Cow<'a, T>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Cow<'a, T>, D::Error>
@@ -954,7 +1011,10 @@ impl<T, E> Deserialize for Result<T, E> where T: Deserialize, E: Deserialize {
impl ::de::Visitor for FieldVisitor { impl ::de::Visitor for FieldVisitor {
type Value = Field; type Value = Field;
#[cfg(any(feature = "std", feature = "collections"))]
fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E> where E: Error { fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E> where E: Error {
#[cfg(feature = "collections")]
use collections::string::ToString;
match value { match value {
0 => Ok(Field::Ok), 0 => Ok(Field::Ok),
1 => Ok(Field::Err), 1 => Ok(Field::Err),
@@ -962,6 +1022,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 { fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: Error {
match value { match value {
"Ok" => Ok(Field::Ok), "Ok" => Ok(Field::Ok),
+23 -3
View File
@@ -1,6 +1,12 @@
//! Generic deserialization framework. //! Generic deserialization framework.
#[cfg(feature = "std")]
use std::error; 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 impls;
pub mod value; pub mod value;
@@ -12,8 +18,13 @@ mod from_primitive;
/// `Deserializer` error. /// `Deserializer` error.
pub trait Error: Sized + error::Error { pub trait Error: Sized + error::Error {
/// Raised when there is general error when deserializing a type. /// Raised when there is general error when deserializing a type.
#[cfg(any(feature = "std", feature = "collections"))]
fn custom<T: Into<String>>(msg: T) -> Self; 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. /// Raised when a `Deserialize` type unexpectedly hit the end of the stream.
fn end_of_stream() -> Self; 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. /// 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 { fn invalid_length(len: usize) -> Self {
Error::custom(format!("Invalid length: {}", len)) Error::custom(format!("Invalid length: {}", len))
} }
@@ -46,6 +60,12 @@ pub trait Error: Sized + error::Error {
fn missing_field(field: &'static str) -> Self { fn missing_field(field: &'static str) -> Self {
Error::custom(format!("Missing field `{}`", field)) Error::custom(format!("Missing field `{}`", field))
} }
/// Raised when a `Deserialize` struct type received more than one of the
/// same struct field.
fn duplicate_field(field: &'static str) -> Self {
Error::custom(format!("Duplicate field `{}`", field))
}
} }
/// `Type` represents all the primitive types that can be deserialized. This is used by /// `Type` represents all the primitive types that can be deserialized. This is used by
@@ -558,9 +578,7 @@ pub trait Visitor {
fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E> fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
// FIXME: this allocation is required in order to be compatible with stable rust, which self.visit_str(::utils::encode_utf8(v).as_str())
// doesn't support encoding a `char` into a stack buffer.
self.visit_string(v.to_string())
} }
/// `visit_str` deserializes a `&str` into a `Value`. /// `visit_str` deserializes a `&str` into a `Value`.
@@ -574,6 +592,7 @@ pub trait Visitor {
/// a copy if it is deserializing a string from a `String` type. By default it passes a `&str` /// a copy if it is deserializing a string from a `String` type. By default it passes a `&str`
/// to the `visit_str` method. /// to the `visit_str` method.
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "collections"))]
fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E> fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
@@ -638,6 +657,7 @@ pub trait Visitor {
} }
/// `visit_byte_buf` deserializes a `Vec<u8>` into a `Value`. /// `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> fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
+72 -4
View File
@@ -1,5 +1,6 @@
//! This module supports deserializing from primitives with the `ValueDeserializer` trait. //! This module supports deserializing from primitives with the `ValueDeserializer` trait.
#[cfg(feature = "std")]
use std::collections::{ use std::collections::{
BTreeMap, BTreeMap,
BTreeSet, BTreeSet,
@@ -10,11 +11,31 @@ use std::collections::{
hash_map, hash_map,
hash_set, hash_set,
}; };
use std::hash::Hash; #[cfg(feature = "std")]
use std::error;
use std::fmt;
use std::vec; 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 de;
use bytes; use bytes;
@@ -25,7 +46,11 @@ use bytes;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Error { pub enum Error {
/// The value had some custom error. /// The value had some custom error.
#[cfg(any(feature = "std", feature = "collections"))]
Custom(String), 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. /// The value had an incorrect type.
InvalidType(de::Type), InvalidType(de::Type),
@@ -34,29 +59,60 @@ pub enum Error {
InvalidLength(usize), InvalidLength(usize),
/// The value is invalid and cannot be deserialized. /// The value is invalid and cannot be deserialized.
#[cfg(any(feature = "std", feature = "collections"))]
InvalidValue(String), 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. /// EOF while deserializing a value.
EndOfStream, EndOfStream,
/// Unknown variant in enum. /// Unknown variant in enum.
#[cfg(any(feature = "std", feature = "collections"))]
UnknownVariant(String), UnknownVariant(String),
/// Unknown variant in enum.
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
UnknownVariant(&'static str),
/// Unknown field in struct. /// Unknown field in struct.
#[cfg(any(feature = "std", feature = "collections"))]
UnknownField(String), UnknownField(String),
/// Unknown field in struct.
#[cfg(all(not(feature = "std"), not(feature = "collections")))]
UnknownField(&'static str),
/// Struct is missing a field. /// Struct is missing a field.
MissingField(&'static str), MissingField(&'static str),
} }
impl de::Error for Error { impl de::Error for Error {
#[cfg(any(feature = "std", feature = "collections"))]
fn custom<T: Into<String>>(msg: T) -> Self { Error::Custom(msg.into()) } 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 end_of_stream() -> Self { Error::EndOfStream }
fn invalid_type(ty: de::Type) -> Self { Error::InvalidType(ty) } 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()) } 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) } 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)) } 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)) } 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) } 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`. /// A helper deserializer that deserializes a `String`.
#[cfg(any(feature = "std", feature = "collections"))]
pub struct StringDeserializer<E>(Option<String>, PhantomData<E>); pub struct StringDeserializer<E>(Option<String>, PhantomData<E>);
#[cfg(any(feature = "std", feature = "collections"))]
impl<E> ValueDeserializer<E> for String impl<E> ValueDeserializer<E> for String
where E: de::Error, 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> impl<E> de::Deserializer for StringDeserializer<E>
where E: de::Error, 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> impl<'a, E> de::VariantVisitor for StringDeserializer<E>
where E: de::Error, 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> impl<T, E> ValueDeserializer<E> for Vec<T>
where T: ValueDeserializer<E>, where T: ValueDeserializer<E>,
E: de::Error, 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> impl<T, E> ValueDeserializer<E> for BTreeSet<T>
where T: ValueDeserializer<E> + Eq + Ord, where T: ValueDeserializer<E> + Eq + Ord,
E: de::Error, 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> impl<T, E> ValueDeserializer<E> for HashSet<T>
where T: ValueDeserializer<E> + Eq + Hash, where T: ValueDeserializer<E> + Eq + Hash,
E: de::Error, 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> impl<K, V, E> ValueDeserializer<E> for BTreeMap<K, V>
where K: ValueDeserializer<E> + Eq + Ord, where K: ValueDeserializer<E> + Eq + Ord,
V: ValueDeserializer<E>, 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> impl<K, V, E> ValueDeserializer<E> for HashMap<K, V>
where K: ValueDeserializer<E> + Eq + Hash, where K: ValueDeserializer<E> + Eq + Hash,
V: ValueDeserializer<E>, 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 impl<E> ValueDeserializer<E> for bytes::ByteBuf
where E: de::Error, where E: de::Error,
{ {
@@ -629,8 +695,10 @@ impl<E> ValueDeserializer<E> for bytes::ByteBuf
} }
/// A helper deserializer that deserializes a `Vec<u8>`. /// A helper deserializer that deserializes a `Vec<u8>`.
#[cfg(any(feature = "std", feature = "collections"))]
pub struct ByteBufDeserializer<E>(Option<Vec<u8>>, PhantomData<E>); pub struct ByteBufDeserializer<E>(Option<Vec<u8>>, PhantomData<E>);
#[cfg(any(feature = "std", feature = "collections"))]
impl<E> de::Deserializer for ByteBufDeserializer<E> impl<E> de::Deserializer for ByteBufDeserializer<E>
where E: de::Error, where E: de::Error,
{ {
+44
View File
@@ -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
View File
@@ -10,23 +10,46 @@
//! [github repository](https://github.com/serde-rs/serde) //! [github repository](https://github.com/serde-rs/serde)
#![doc(html_root_url="https://serde-rs.github.io/serde/serde")] #![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
#![cfg_attr(feature = "nightly", feature(collections, enumset, nonzero, plugin, step_trait, #![cfg_attr(not(feature = "std"), no_std)]
zero_one))] #![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", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", allow(linkedlist))] #![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)] #![deny(missing_docs)]
#[cfg(feature = "nightly")] #[cfg(all(feature = "nightly", feature = "collections"))]
extern crate collections; extern crate collections;
#[cfg(feature = "nightly")] #[cfg(all(feature = "nightly", feature = "alloc"))]
extern crate core; 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 ser::{Serialize, Serializer};
pub use de::{Deserialize, Deserializer, Error}; pub use de::{Deserialize, Deserializer, Error};
#[cfg(not(feature = "std"))]
macro_rules! format {
($s:expr, $($rest:tt)*) => ($s)
}
pub mod bytes; pub mod bytes;
pub mod de; pub mod de;
#[cfg(feature = "std")]
pub mod iter; pub mod iter;
pub mod ser; pub mod ser;
#[cfg(not(feature = "std"))]
pub mod error;
mod utils;
+60 -8
View File
@@ -1,6 +1,11 @@
//! Implementations for all of Rust's builtin types. //! Implementations for all of Rust's builtin types.
#[cfg(feature = "std")]
use std::borrow::Cow; use std::borrow::Cow;
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::borrow::Cow;
#[cfg(feature = "std")]
use std::collections::{ use std::collections::{
BinaryHeap, BinaryHeap,
BTreeMap, BTreeMap,
@@ -10,20 +15,47 @@ use std::collections::{
HashSet, HashSet,
VecDeque, 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 collections::enum_set::{CLike, EnumSet};
use std::hash::Hash; #[cfg(all(feature = "nightly", feature = "collections"))]
use collections::borrow::ToOwned;
use core::hash::Hash;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use std::iter; use core::iter;
#[cfg(feature = "std")]
use std::net; use std::net;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use std::num; use core::num;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use std::ops; use core::ops;
#[cfg(feature = "std")]
use std::path; use std::path;
#[cfg(feature = "std")]
use std::rc::Rc; use std::rc::Rc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::rc::Rc;
#[cfg(feature = "std")]
use std::sync::Arc; 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")] #[cfg(feature = "nightly")]
use core::nonzero::{NonZero, Zeroable}; use core::nonzero::{NonZero, Zeroable};
@@ -77,6 +109,7 @@ impl Serialize for str {
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
impl Serialize for String { impl Serialize for String {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> 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> impl<T> Serialize for BinaryHeap<T>
where T: Serialize + Ord 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> impl<T> Serialize for BTreeSet<T>
where T: Serialize + Ord, 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> impl<T> Serialize for EnumSet<T>
where T: Serialize + CLike where T: Serialize + CLike
{ {
@@ -294,6 +329,7 @@ impl<T> Serialize for EnumSet<T>
} }
} }
#[cfg(feature = "std")]
impl<T> Serialize for HashSet<T> impl<T> Serialize for HashSet<T>
where T: Serialize + Eq + Hash, where T: Serialize + Eq + Hash,
{ {
@@ -305,6 +341,7 @@ impl<T> Serialize for HashSet<T>
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for LinkedList<T> impl<T> Serialize for LinkedList<T>
where T: Serialize, where T: Serialize,
{ {
@@ -330,6 +367,7 @@ impl<A> Serialize for ops::Range<A>
} }
} }
#[cfg(any(feature = "std", feature = "collections"))]
impl<T> Serialize for Vec<T> where T: Serialize { impl<T> Serialize for Vec<T> where T: Serialize {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -339,6 +377,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 { impl<T> Serialize for VecDeque<T> where T: Serialize {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -598,6 +637,7 @@ impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
impl<K, V> Serialize for BTreeMap<K, V> impl<K, V> Serialize for BTreeMap<K, V>
where K: Serialize + Ord, where K: Serialize + Ord,
V: Serialize, V: Serialize,
@@ -610,6 +650,7 @@ impl<K, V> Serialize for BTreeMap<K, V>
} }
} }
#[cfg(feature = "std")]
impl<K, V> Serialize for HashMap<K, V> impl<K, V> Serialize for HashMap<K, V>
where K: Serialize + Eq + Hash, where K: Serialize + Eq + Hash,
V: Serialize, V: Serialize,
@@ -642,6 +683,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 { impl<T: ?Sized> Serialize for Box<T> where T: Serialize {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -651,6 +693,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, { impl<T> Serialize for Rc<T> where T: Serialize, {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -660,6 +703,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, { impl<T> Serialize for Arc<T> where T: Serialize, {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -669,6 +713,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, { impl<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned, {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@@ -695,7 +740,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 { impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -707,6 +752,7 @@ impl Serialize for net::IpAddr {
} }
} }
#[cfg(feature = "std")]
impl Serialize for net::Ipv4Addr { impl Serialize for net::Ipv4Addr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -715,6 +761,7 @@ impl Serialize for net::Ipv4Addr {
} }
} }
#[cfg(feature = "std")]
impl Serialize for net::Ipv6Addr { impl Serialize for net::Ipv6Addr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -725,6 +772,7 @@ impl Serialize for net::Ipv6Addr {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Serialize for net::SocketAddr { impl Serialize for net::SocketAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -736,6 +784,7 @@ impl Serialize for net::SocketAddr {
} }
} }
#[cfg(feature = "std")]
impl Serialize for net::SocketAddrV4 { impl Serialize for net::SocketAddrV4 {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -744,6 +793,7 @@ impl Serialize for net::SocketAddrV4 {
} }
} }
#[cfg(feature = "std")]
impl Serialize for net::SocketAddrV6 { impl Serialize for net::SocketAddrV6 {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -754,6 +804,7 @@ impl Serialize for net::SocketAddrV6 {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Serialize for path::Path { impl Serialize for path::Path {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
@@ -765,6 +816,7 @@ impl Serialize for path::Path {
} }
} }
#[cfg(feature = "std")]
impl Serialize for path::PathBuf { impl Serialize for path::PathBuf {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer, where S: Serializer,
+12 -3
View File
@@ -1,6 +1,12 @@
//! Generic serialization framework. //! Generic serialization framework.
#[cfg(feature = "std")]
use std::error; use std::error;
#[cfg(not(feature = "std"))]
use error;
#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;
pub mod impls; pub mod impls;
@@ -10,8 +16,13 @@ pub mod impls;
/// `Serializer` error. /// `Serializer` error.
pub trait Error: Sized + error::Error { pub trait Error: Sized + error::Error {
/// Raised when there is general error when deserializing a type. /// Raised when there is general error when deserializing a type.
#[cfg(any(feature = "std", feature = "collections"))]
fn custom<T: Into<String>>(msg: T) -> Self; 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. /// Raised when a `Serialize` was passed an incorrect value.
fn invalid_value(msg: &str) -> Self { fn invalid_value(msg: &str) -> Self {
Error::custom(format!("invalid value: {}", msg)) Error::custom(format!("invalid value: {}", msg))
@@ -115,9 +126,7 @@ pub trait Serializer {
/// single character. /// single character.
#[inline] #[inline]
fn serialize_char(&mut self, v: char) -> Result<(), Self::Error> { fn serialize_char(&mut self, v: char) -> Result<(), Self::Error> {
// FIXME: this allocation is required in order to be compatible with stable rust, which self.serialize_str(::utils::encode_utf8(v).as_str())
// doesn't support encoding a `char` into a stack buffer.
self.serialize_str(&v.to_string())
} }
/// Serializes a `&str`. /// Serializes a `&str`.
+72
View File
@@ -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)
}
+9 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen" name = "serde_codegen"
version = "0.7.4" version = "0.7.7"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" description = "Macros to auto-generate implementations for the serde framework"
@@ -8,6 +8,7 @@ repository = "https://github.com/serde-rs/serde"
documentation = "https://github.com/serde-rs/serde" documentation = "https://github.com/serde-rs/serde"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
build = "build.rs" build = "build.rs"
include = ["Cargo.toml", "build.rs", "src/**/*.rs"]
[features] [features]
default = ["with-syntex"] default = ["with-syntex"]
@@ -16,13 +17,13 @@ nightly-testing = ["clippy"]
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"] with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
[build-dependencies] [build-dependencies]
quasi_codegen = { version = "^0.10.0", optional = true } quasi_codegen = { version = "^0.11.0", optional = true }
syntex = { version = "^0.31.0", optional = true } syntex = { version = "^0.33.0", optional = true }
[dependencies] [dependencies]
aster = { version = "^0.16.0", default-features = false } aster = { version = "^0.17.0", default-features = false }
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
quasi = { version = "^0.10.0", default-features = false } quasi = { version = "^0.11.0", default-features = false }
quasi_macros = { version = "^0.10.0", optional = true } quasi_macros = { version = "^0.11.0", optional = true }
syntex = { version = "^0.32.0", optional = true } syntex = { version = "^0.33.0", optional = true }
syntex_syntax = { version = "^0.32.0", optional = true } syntex_syntax = { version = "^0.33.0", optional = true }
+33 -195
View File
@@ -177,36 +177,32 @@ pub struct FieldAttrs {
name: Name, name: Name,
skip_serializing_field: bool, skip_serializing_field: bool,
skip_deserializing_field: bool, skip_deserializing_field: bool,
skip_serializing_field_if: Option<P<ast::Expr>>, skip_serializing_if: Option<ast::Path>,
default_expr_if_missing: Option<P<ast::Expr>>, default_expr_if_missing: Option<P<ast::Expr>>,
serialize_with: Option<P<ast::Expr>>, serialize_with: Option<ast::Path>,
deserialize_with: P<ast::Expr>, deserialize_with: Option<ast::Path>,
} }
impl FieldAttrs { impl FieldAttrs {
/// Extract out the `#[serde(...)]` attributes from a struct field. /// Extract out the `#[serde(...)]` attributes from a struct field.
pub fn from_field(cx: &ExtCtxt, pub fn from_field(cx: &ExtCtxt,
container_ty: &P<ast::Ty>, index: usize,
generics: &ast::Generics, field: &ast::StructField) -> Result<Self, Error> {
field: &ast::StructField,
is_enum: bool) -> Result<Self, Error> {
let builder = AstBuilder::new(); let builder = AstBuilder::new();
let field_ident = match field.ident { let field_ident = match field.ident {
Some(ident) => ident, Some(ident) => ident,
None => { cx.span_bug(field.span, "struct field has no name?") } None => builder.id(index.to_string()),
}; };
let identity = quote_expr!(cx, |x| x);
let mut field_attrs = FieldAttrs { let mut field_attrs = FieldAttrs {
name: Name::new(field_ident), name: Name::new(field_ident),
skip_serializing_field: false, skip_serializing_field: false,
skip_deserializing_field: false, skip_deserializing_field: false,
skip_serializing_field_if: None, skip_serializing_if: None,
default_expr_if_missing: None, default_expr_if_missing: None,
serialize_with: None, serialize_with: None,
deserialize_with: identity, deserialize_with: None,
}; };
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
@@ -262,39 +258,20 @@ impl FieldAttrs {
// Parse `#[serde(skip_serializing_if="...")]` // Parse `#[serde(skip_serializing_if="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
let expr = wrap_skip_serializing( let path = try!(parse_lit_into_path(cx, name, lit));
field_ident, field_attrs.skip_serializing_if = Some(path);
try!(parse_lit_into_path(cx, name, lit)),
is_enum,
);
field_attrs.skip_serializing_field_if = Some(expr);
} }
// Parse `#[serde(serialize_with="...")]` // Parse `#[serde(serialize_with="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => {
let expr = wrap_serialize_with( let path = try!(parse_lit_into_path(cx, name, lit));
cx, field_attrs.serialize_with = Some(path);
container_ty,
generics,
field_ident,
try!(parse_lit_into_path(cx, name, lit)),
is_enum,
);
field_attrs.serialize_with = Some(expr);
} }
// Parse `#[serde(deserialize_with="...")]` // Parse `#[serde(deserialize_with="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
let expr = wrap_deserialize_with( let path = try!(parse_lit_into_path(cx, name, lit));
cx, field_attrs.deserialize_with = Some(path);
&field.ty,
generics,
try!(parse_lit_into_path(cx, name, lit)),
);
field_attrs.deserialize_with = expr;
} }
_ => { _ => {
@@ -316,22 +293,6 @@ impl FieldAttrs {
&self.name &self.name
} }
/// Predicate for using a field's default value
pub fn expr_is_missing(&self) -> P<ast::Expr> {
match self.default_expr_if_missing {
Some(ref expr) => expr.clone(),
None => {
let name = self.name.deserialize_name_expr();
AstBuilder::new().expr()
.try()
.method_call("missing_field").id("visitor")
.with_arg(name)
.build()
}
}
}
/// Predicate for ignoring a field when serializing a value
pub fn skip_serializing_field(&self) -> bool { pub fn skip_serializing_field(&self) -> bool {
self.skip_serializing_field self.skip_serializing_field
} }
@@ -340,28 +301,35 @@ impl FieldAttrs {
self.skip_deserializing_field self.skip_deserializing_field
} }
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> { pub fn skip_serializing_if(&self) -> Option<&ast::Path> {
self.skip_serializing_field_if.as_ref() self.skip_serializing_if.as_ref()
} }
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> { pub fn default_expr_if_missing(&self) -> Option<&P<ast::Expr>> {
self.default_expr_if_missing.as_ref()
}
pub fn serialize_with(&self) -> Option<&ast::Path> {
self.serialize_with.as_ref() self.serialize_with.as_ref()
} }
pub fn deserialize_with(&self) -> &P<ast::Expr> { pub fn deserialize_with(&self) -> Option<&ast::Path> {
&self.deserialize_with self.deserialize_with.as_ref()
} }
} }
/// Extract out the `#[serde(...)]` attributes from a struct field. /// Zip together fields and `#[serde(...)]` attributes on those fields.
pub fn get_struct_field_attrs(cx: &ExtCtxt, pub fn fields_with_attrs<'a>(
container_ty: &P<ast::Ty>, cx: &ExtCtxt,
generics: &ast::Generics, fields: &'a [ast::StructField],
fields: &[ast::StructField], ) -> Result<Vec<(&'a ast::StructField, FieldAttrs)>, Error> {
is_enum: bool) -> Result<Vec<FieldAttrs>, Error> {
fields.iter() 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, attrs))
})
.collect() .collect()
} }
@@ -515,133 +483,3 @@ fn wrap_default(path: ast::Path) -> P<ast::Expr> {
.build_path(path) .build_path(path)
.build() .build()
} }
/// 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,
}
})
}
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in a trait to prevent
/// it from accessing the internal `Deserialize` state.
fn wrap_deserialize_with(cx: &ExtCtxt,
field_ty: &P<ast::Ty>,
generics: &ast::Generics,
path: ast::Path) -> P<ast::Expr> {
// Quasi-quoting doesn't do a great job of expanding generics into paths, so manually build it.
let ty_path = AstBuilder::new().path()
.segment("__SerdeDeserializeWithStruct")
.with_generics(generics.clone())
.build()
.build();
let where_clause = &generics.where_clause;
quote_expr!(cx, ({
struct __SerdeDeserializeWithStruct $generics $where_clause {
value: $field_ty,
}
impl $generics _serde::de::Deserialize for $ty_path $where_clause {
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
where D: _serde::de::Deserializer
{
let value = try!($path(deserializer));
Ok(__SerdeDeserializeWithStruct { value: value })
}
}
|visit: $ty_path| visit.value
}))
}
+4 -4
View File
@@ -139,9 +139,9 @@ fn contains_generic(ty: &ast::Ty, generics: &ast::Generics) -> bool {
// //
// impl<'a, T> Serialize for Test<'a, T> // impl<'a, T> Serialize for Test<'a, T>
// where T: Serialize { ... } // where T: Serialize { ... }
fn strip_reference(ty: &P<ast::Ty>) -> &P<ast::Ty> { fn strip_reference(mut ty: &P<ast::Ty>) -> &P<ast::Ty> {
match ty.node { while let ast::TyKind::Rptr(_, ref mut_ty) = ty.node {
ast::TyKind::Rptr(_, ref mut_ty) => &mut_ty.ty, ty = &mut_ty.ty;
_ => ty
} }
ty
} }
+315 -303
View File
@@ -9,7 +9,6 @@ use syntax::ast::{
}; };
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString; use syntax::parse::token::InternedString;
use syntax::ptr::P; use syntax::ptr::P;
@@ -113,22 +112,7 @@ fn deserialized_by_us(field: &ast::StructField) -> bool {
return false return false
} }
ast::MetaItemKind::NameValue(ref name, _) if name == &"deserialize_with" => { ast::MetaItemKind::NameValue(ref name, _) if name == &"deserialize_with" => {
// TODO: For now we require `T: Deserialize` even if the return false
// field has `deserialize_with`. The reason is the signature
// of serde::de::MapVisitor::missing_field which looks like:
//
// fn missing_field<T>(...) -> Result<T, Self::Error> where T: Deserialize
//
// So in order to use missing_field, the type must have the
// `T: Deserialize` bound. Some formats rely on this bound
// because they treat missing fields as unit.
//
// Long-term the fix would be to change the signature of
// missing_field so it can, for example, use the
// `deserialize_with` function to visit a unit in place of
// the missing field.
//
// See https://github.com/serde-rs/serde/issues/259
} }
_ => {} _ => {}
} }
@@ -218,28 +202,19 @@ fn deserialize_item_struct(
container_attrs, 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, _) => { ast::VariantData::Tuple(ref fields, _) => {
if fields.iter().any(|field| field.ident.is_some()) { if fields.iter().any(|field| field.ident.is_some()) {
cx.span_bug(span, "tuple struct has named fields") cx.span_bug(span, "tuple struct has named fields")
} }
deserialize_tuple_struct( deserialize_tuple(
cx, cx,
&builder, &builder,
item.ident, item.ident,
None,
impl_generics, impl_generics,
ty, ty,
fields.len(), fields,
container_attrs, container_attrs,
) )
} }
@@ -252,6 +227,7 @@ fn deserialize_item_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
None,
impl_generics, impl_generics,
ty, ty,
fields, fields,
@@ -356,15 +332,15 @@ fn deserialize_unit_struct(
type Value = $type_ident; type Value = $type_ident;
#[inline] #[inline]
fn visit_unit<E>(&mut self) -> ::std::result::Result<$type_ident, E> fn visit_unit<__E>(&mut self) -> ::std::result::Result<$type_ident, __E>
where E: _serde::de::Error, where __E: _serde::de::Error,
{ {
Ok($type_ident) Ok($type_ident)
} }
#[inline] #[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> ::std::result::Result<$type_ident, V::Error> fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$type_ident, __V::Error>
where V: _serde::de::SeqVisitor, where __V: _serde::de::SeqVisitor,
{ {
try!(visitor.end()); try!(visitor.end());
self.visit_unit() self.visit_unit()
@@ -375,12 +351,14 @@ fn deserialize_unit_struct(
})) }))
} }
fn deserialize_newtype_struct( fn deserialize_tuple(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
variant_ident: Option<Ident>,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: &[ast::StructField],
container_attrs: &attr::ContainerAttrs, container_attrs: &attr::ContainerAttrs,
) -> Result<P<ast::Expr>, Error> { ) -> Result<P<ast::Expr>, Error> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@@ -392,67 +370,50 @@ fn deserialize_newtype_struct(
vec![deserializer_ty_arg(builder)], 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, cx,
builder, builder,
builder.path().id(type_ident).build(), type_ident,
1, type_path,
);
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<D>(&mut self, deserializer: &mut D) -> ::std::result::Result<Self::Value, D::Error>
where D: _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,
impl_generics, impl_generics,
vec![deserializer_ty_param(builder)], &fields_with_attrs,
vec![deserializer_ty_arg(builder)], false,
)); ));
let visit_seq_expr = deserialize_seq( let dispatch = if is_enum {
cx, quote_expr!(cx,
builder, visitor.visit_tuple($nfields, $visitor_expr))
builder.path().id(type_ident).build(), } else if nfields == 1 {
fields, let type_name = container_attrs.name().deserialize_name_expr();
); quote_expr!(cx,
deserializer.deserialize_newtype_struct($type_name, $visitor_expr))
let type_name = container_attrs.name().deserialize_name_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, { Ok(quote_expr!(cx, {
$visitor_item $visitor_item
@@ -460,6 +421,8 @@ fn deserialize_tuple_struct(
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
$visit_newtype_struct
#[inline] #[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: _serde::de::SeqVisitor, where __V: _serde::de::SeqVisitor,
@@ -468,64 +431,47 @@ fn deserialize_tuple_struct(
} }
} }
deserializer.deserialize_tuple_struct($type_name, $fields, $visitor_expr) $dispatch
})) }))
} }
fn deserialize_seq( fn deserialize_seq(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, type_ident: Ident,
fields: usize, type_path: ast::Path,
) -> P<ast::Expr> { impl_generics: &ast::Generics,
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,
struct_path: ast::Path,
fields: &[(&ast::StructField, attr::FieldAttrs)], fields: &[(&ast::StructField, attr::FieldAttrs)],
is_struct: bool,
) -> Result<P<ast::Expr>, Error> { ) -> Result<P<ast::Expr>, Error> {
let let_values: Vec<_> = fields.iter() let let_values: Vec<_> = fields.iter()
.enumerate() .enumerate()
.map(|(i, &(_, ref attrs))| { .map(|(i, &(field, ref attrs))| {
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
if attrs.skip_deserializing_field() { if attrs.skip_deserializing_field() {
let default = attrs.expr_is_missing(); let default = expr_is_missing(cx, attrs);
quote_stmt!(cx, quote_stmt!(cx,
let $name = $default; let $name = $default;
).unwrap() ).unwrap()
} else { } else {
let deserialize_with = attrs.deserialize_with(); let visit = match attrs.deserialize_with() {
None => {
let field_ty = &field.ty;
quote_expr!(cx, try!(visitor.visit::<$field_ty>()))
}
Some(path) => {
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
cx, builder, type_ident, impl_generics, &field.ty, path);
quote_expr!(cx, {
$wrapper
$wrapper_impl
try!(visitor.visit::<$wrapper_ty>()).map(|wrap| wrap.value)
})
}
};
quote_stmt!(cx, quote_stmt!(cx,
let $name = match try!(visitor.visit()) { let $name = match $visit {
Some(value) => { $deserialize_with(value) }, Some(value) => { value },
None => { None => {
return Err(_serde::de::Error::end_of_stream()); return Err(_serde::de::Error::end_of_stream());
} }
@@ -535,23 +481,30 @@ fn deserialize_struct_as_seq(
}) })
.collect(); .collect();
let result = builder.expr().struct_path(struct_path) let result = if is_struct {
.with_id_exprs( builder.expr().struct_path(type_path)
fields.iter() .with_id_exprs(
.enumerate() fields.iter()
.map(|(i, &(field, _))| { .enumerate()
( .map(|(i, &(field, _))| {
match field.ident { (
Some(name) => name.clone(), match field.ident {
None => { Some(name) => name.clone(),
cx.span_bug(field.span, "struct contains unnamed fields") None => {
} cx.span_bug(field.span, "struct contains unnamed fields")
}, }
builder.expr().id(format!("__field{}", i)), },
) builder.expr().id(format!("__field{}", i)),
}) )
) })
.build(); )
.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, { Ok(quote_expr!(cx, {
$let_values $let_values
@@ -562,10 +515,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 &(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( fn deserialize_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
variant_ident: Option<Ident>,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
@@ -580,26 +569,42 @@ fn deserialize_struct(
vec![deserializer_ty_arg(builder)], 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, cx,
builder, builder,
type_ident,
type_path.clone(), type_path.clone(),
impl_generics,
&fields_with_attrs, &fields_with_attrs,
true,
)); ));
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor( let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
cx, cx,
builder, builder,
type_ident,
type_path.clone(), type_path.clone(),
impl_generics,
&fields_with_attrs, &fields_with_attrs,
container_attrs, 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, { Ok(quote_expr!(cx, {
$field_visitor $field_visitor
@@ -626,7 +631,7 @@ fn deserialize_struct(
$fields_stmt $fields_stmt
deserializer.deserialize_struct($type_name, FIELDS, $visitor_expr) $dispatch
})) }))
} }
@@ -747,29 +752,34 @@ fn deserialize_variant(
Ok($type_ident::$variant_ident) Ok($type_ident::$variant_ident)
})) }))
} }
ast::VariantData::Tuple(ref args, _) if args.len() == 1 => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
Ok(quote_expr!(cx, { deserialize_newtype_variant(
let val = try!(visitor.visit_newtype());
Ok($type_ident::$variant_ident(val))
}))
}
ast::VariantData::Tuple(ref fields, _) => {
deserialize_tuple_variant(
cx, cx,
builder, builder,
type_ident, type_ident,
variant_ident, variant_ident,
generics, generics,
ty, &fields[0],
fields.len(),
) )
} }
ast::VariantData::Struct(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
deserialize_struct_variant( deserialize_tuple(
cx, cx,
builder, builder,
type_ident, 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, generics,
ty, ty,
fields, fields,
@@ -779,116 +789,31 @@ fn deserialize_variant(
} }
} }
fn deserialize_tuple_variant( fn deserialize_newtype_variant(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: ast::Ident, type_ident: Ident,
variant_ident: ast::Ident, variant_ident: Ident,
generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, field: &ast::StructField,
fields: usize,
) -> Result<P<ast::Expr>, Error> { ) -> Result<P<ast::Expr>, Error> {
let where_clause = &generics.where_clause; let attrs = try!(attr::FieldAttrs::from_field(cx, 0, field));
let visit = match attrs.deserialize_with() {
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor( None => {
builder, let field_ty = &field.ty;
generics, quote_expr!(cx, try!(visitor.visit_newtype::<$field_ty>()))
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
}
} }
Some(path) => {
visitor.visit_tuple($fields, $visitor_expr) let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
})) cx, builder, type_ident, impl_generics, &field.ty, path);
} quote_expr!(cx, {
$wrapper
fn deserialize_struct_variant( $wrapper_impl
cx: &ExtCtxt, try!(visitor.visit_newtype::<$wrapper_ty>()).value
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_path.clone(),
&fields_with_attrs,
));
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
cx,
builder,
type_path,
&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
}
} }
};
$fields_stmt Ok(quote_expr!(cx, Ok($type_ident::$variant_ident($visit))))
visitor.visit_struct(FIELDS, $visitor_expr)
}))
} }
fn deserialize_field_visitor( fn deserialize_field_visitor(
@@ -1008,13 +933,11 @@ fn deserialize_field_visitor(
let impl_item = quote_item!(cx, let impl_item = quote_item!(cx,
impl _serde::de::Deserialize for __Field { impl _serde::de::Deserialize for __Field {
#[inline] #[inline]
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error> fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<__Field, __D::Error>
where D: _serde::de::Deserializer, where __D: _serde::de::Deserializer,
{ {
use std::marker::PhantomData; struct __FieldVisitor<__D> {
phantom: ::std::marker::PhantomData<__D>
struct __FieldVisitor<D> {
phantom: PhantomData<D>
} }
impl<__D> _serde::de::Visitor for __FieldVisitor<__D> impl<__D> _serde::de::Visitor for __FieldVisitor<__D>
@@ -1022,26 +945,30 @@ fn deserialize_field_visitor(
{ {
type Value = __Field; type Value = __Field;
fn visit_usize<E>(&mut self, value: usize) -> ::std::result::Result<__Field, E> fn visit_usize<__E>(&mut self, value: usize) -> ::std::result::Result<__Field, __E>
where E: _serde::de::Error, where __E: _serde::de::Error,
{ {
$index_body $index_body
} }
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E> fn visit_str<__E>(&mut self, value: &str) -> ::std::result::Result<__Field, __E>
where E: _serde::de::Error, where __E: _serde::de::Error,
{ {
$str_body $str_body
} }
fn visit_bytes<E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, E> fn visit_bytes<__E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, __E>
where E: _serde::de::Error, where __E: _serde::de::Error,
{ {
$bytes_body $bytes_body
} }
} }
deserializer.deserialize_struct_field(__FieldVisitor::<D>{ phantom: PhantomData }) deserializer.deserialize_struct_field(
__FieldVisitor::<__D>{
phantom: ::std::marker::PhantomData
}
)
} }
} }
).unwrap(); ).unwrap();
@@ -1052,7 +979,9 @@ fn deserialize_field_visitor(
fn deserialize_struct_visitor( fn deserialize_struct_visitor(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident,
struct_path: ast::Path, struct_path: ast::Path,
impl_generics: &ast::Generics,
fields: &[(&ast::StructField, attr::FieldAttrs)], fields: &[(&ast::StructField, attr::FieldAttrs)],
container_attrs: &attr::ContainerAttrs, container_attrs: &attr::ContainerAttrs,
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> { ) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
@@ -1071,7 +1000,9 @@ fn deserialize_struct_visitor(
let visit_map_expr = try!(deserialize_map( let visit_map_expr = try!(deserialize_map(
cx, cx,
builder, builder,
type_ident,
struct_path, struct_path,
impl_generics,
fields, fields,
container_attrs, container_attrs,
)); ));
@@ -1100,7 +1031,9 @@ fn deserialize_struct_visitor(
fn deserialize_map( fn deserialize_map(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident,
struct_path: ast::Path, struct_path: ast::Path,
impl_generics: &ast::Generics,
fields: &[(&ast::StructField, attr::FieldAttrs)], fields: &[(&ast::StructField, attr::FieldAttrs)],
container_attrs: &attr::ContainerAttrs, container_attrs: &attr::ContainerAttrs,
) -> Result<P<ast::Expr>, Error> { ) -> Result<P<ast::Expr>, Error> {
@@ -1114,17 +1047,40 @@ fn deserialize_map(
// Declare each field that will be deserialized. // Declare each field that will be deserialized.
let let_values: Vec<ast::Stmt> = fields_attrs_names.iter() let let_values: Vec<ast::Stmt> = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
.map(|&(_, _, name)| quote_stmt!(cx, let mut $name = None;).unwrap()) .map(|&(field, _, name)| {
let field_ty = &field.ty;
quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap()
})
.collect(); .collect();
// Match arms to extract a value for a field. // Match arms to extract a value for a field.
let value_arms = fields_attrs_names.iter() let value_arms = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
.map(|&(_, ref attrs, name)| { .map(|&(field, ref attrs, name)| {
let deserialize_with = attrs.deserialize_with(); let deser_name = attrs.name().deserialize_name();
let name_str = builder.expr().lit().str(deser_name);
let visit = match attrs.deserialize_with() {
None => {
let field_ty = &field.ty;
quote_expr!(cx, try!(visitor.visit_value::<$field_ty>()))
}
Some(path) => {
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
cx, builder, type_ident, impl_generics, &field.ty, path);
quote_expr!(cx, ({
$wrapper
$wrapper_impl
try!(visitor.visit_value::<$wrapper_ty>()).value
}))
}
};
quote_arm!(cx, quote_arm!(cx,
__Field::$name => { __Field::$name => {
$name = Some($deserialize_with(try!(visitor.visit_value()))); if $name.is_some() {
return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str));
}
$name = Some($visit);
} }
) )
}) })
@@ -1155,7 +1111,7 @@ fn deserialize_map(
let extract_values = fields_attrs_names.iter() let extract_values = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
.map(|&(_, ref attrs, name)| { .map(|&(_, ref attrs, name)| {
let missing_expr = attrs.expr_is_missing(); let missing_expr = expr_is_missing(cx, attrs);
Ok(quote_stmt!(cx, Ok(quote_stmt!(cx,
let $name = match $name { let $name = match $name {
@@ -1180,7 +1136,7 @@ fn deserialize_map(
} }
}, },
if attrs.skip_deserializing_field() { if attrs.skip_deserializing_field() {
attrs.expr_is_missing() expr_is_missing(cx, attrs)
} else { } else {
builder.expr().id(name) builder.expr().id(name)
} }
@@ -1192,7 +1148,7 @@ fn deserialize_map(
Ok(quote_expr!(cx, { Ok(quote_expr!(cx, {
$let_values $let_values
while let Some(key) = try!(visitor.visit_key()) { while let Some(key) = try!(visitor.visit_key::<__Field>()) {
match key { match key {
$value_arms $value_arms
$skipped_arms $skipped_arms
@@ -1208,17 +1164,73 @@ fn deserialize_map(
})) }))
} }
fn fields_with_attrs<'a>( /// This function wraps the expression in `#[serde(deserialize_with="...")]` in
/// a trait to prevent it from accessing the internal `Deserialize` state.
fn wrap_deserialize_with(
cx: &ExtCtxt, cx: &ExtCtxt,
generics: &ast::Generics, builder: &aster::AstBuilder,
ty: &P<ast::Ty>, type_ident: Ident,
fields: &'a [ast::StructField], impl_generics: &ast::Generics,
is_enum: bool field_ty: &P<ast::Ty>,
) -> Result<Vec<(&'a ast::StructField, attr::FieldAttrs)>, Error> { deserialize_with: &ast::Path,
fields.iter() ) -> (ast::Stmt, ast::Stmt, ast::Path) {
.map(|field| { // Quasi-quoting doesn't do a great job of expanding generics into paths,
let attrs = try!(attr::FieldAttrs::from_field(cx, &ty, generics, field, is_enum)); // so manually build it.
Ok((field, attrs)) let wrapper_ty = builder.path()
}) .segment("__SerdeDeserializeWithStruct")
.collect() .with_generics(impl_generics.clone())
.build()
.build();
let where_clause = &impl_generics.where_clause;
let phantom_ty = builder.path()
.segment(type_ident)
.with_generics(builder.from_generics(impl_generics.clone())
.strip_ty_params()
.build())
.build()
.build();
(
quote_stmt!(cx,
struct __SerdeDeserializeWithStruct $impl_generics $where_clause {
value: $field_ty,
phantom: ::std::marker::PhantomData<$phantom_ty>,
}
).unwrap(),
quote_stmt!(cx,
impl $impl_generics _serde::de::Deserialize for $wrapper_ty $where_clause {
fn deserialize<__D>(__d: &mut __D) -> ::std::result::Result<Self, __D::Error>
where __D: _serde::de::Deserializer
{
let value = try!($deserialize_with(__d));
Ok(__SerdeDeserializeWithStruct {
value: value,
phantom: ::std::marker::PhantomData,
})
}
}
).unwrap(),
wrapper_ty,
)
}
fn expr_is_missing(
cx: &ExtCtxt,
attrs: &attr::FieldAttrs,
) -> P<ast::Expr> {
if let Some(expr) = attrs.default_expr_if_missing() {
return expr.clone();
}
let name = attrs.name().deserialize_name_expr();
match attrs.deserialize_with() {
None => {
quote_expr!(cx, try!(visitor.missing_field($name)))
}
Some(_) => {
quote_expr!(cx, return Err(
<__V::Error as _serde::de::Error>::missing_field($name)))
}
}
} }
+176 -78
View File
@@ -185,6 +185,10 @@ fn serialize_item_struct(
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
serialize_newtype_struct( serialize_newtype_struct(
cx, cx,
&builder,
impl_generics,
ty,
&fields[0],
container_attrs, container_attrs,
) )
} }
@@ -198,7 +202,7 @@ fn serialize_item_struct(
&builder, &builder,
impl_generics, impl_generics,
ty, ty,
fields.len(), fields,
container_attrs, container_attrs,
) )
} }
@@ -232,12 +236,24 @@ fn serialize_unit_struct(
fn serialize_newtype_struct( fn serialize_newtype_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder,
impl_generics: &ast::Generics,
container_ty: P<ast::Ty>,
field: &ast::StructField,
container_attrs: &attr::ContainerAttrs, container_attrs: &attr::ContainerAttrs,
) -> Result<P<ast::Expr>, Error> { ) -> Result<P<ast::Expr>, Error> {
let type_name = container_attrs.name().serialize_name_expr(); 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, Ok(quote_expr!(cx,
_serializer.serialize_newtype_struct($type_name, &self.0) _serializer.serialize_newtype_struct($type_name, $field_expr)
)) ))
} }
@@ -246,10 +262,10 @@ fn serialize_tuple_struct(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: &[ast::StructField],
container_attrs: &attr::ContainerAttrs, container_attrs: &attr::ContainerAttrs,
) -> Result<P<ast::Expr>, Error> { ) -> 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, cx,
builder, builder,
ty.clone(), ty.clone(),
@@ -260,7 +276,8 @@ fn serialize_tuple_struct(
builder.id("serialize_tuple_struct_elt"), builder.id("serialize_tuple_struct_elt"),
fields, fields,
impl_generics, impl_generics,
); false,
));
let type_name = container_attrs.name().serialize_name_expr(); let type_name = container_attrs.name().serialize_name_expr();
@@ -362,12 +379,8 @@ fn serialize_variant(
match variant.node.data { match variant.node.data {
ast::VariantData::Unit(_) => { ast::VariantData::Unit(_) => {
let pat = builder.pat().path()
.id(type_ident).id(variant_ident)
.build();
Ok(quote_arm!(cx, Ok(quote_arm!(cx,
$pat => { $type_ident::$variant_ident => {
_serde::ser::Serializer::serialize_unit_variant( _serde::ser::Serializer::serialize_unit_variant(
_serializer, _serializer,
$type_name, $type_name,
@@ -378,23 +391,19 @@ fn serialize_variant(
)) ))
}, },
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
let field = builder.id("__simple_value"); let expr = try!(serialize_newtype_variant(
let field = builder.pat().ref_id(field); cx,
let pat = builder.pat().enum_() builder,
.id(type_ident).id(variant_ident).build() type_name,
.with_pats(Some(field).into_iter()) variant_index,
.build(); variant_name,
ty,
generics,
&fields[0],
));
Ok(quote_arm!(cx, Ok(quote_arm!(cx,
$pat => { $type_ident::$variant_ident(ref __simple_value) => { $expr }
_serde::ser::Serializer::serialize_newtype_variant(
_serializer,
$type_name,
$variant_index,
$variant_name,
__simple_value,
)
}
)) ))
}, },
ast::VariantData::Tuple(ref fields, _) => { ast::VariantData::Tuple(ref fields, _) => {
@@ -410,7 +419,7 @@ fn serialize_variant(
) )
.build(); .build();
let expr = serialize_tuple_variant( let expr = try!(serialize_tuple_variant(
cx, cx,
builder, builder,
type_name, type_name,
@@ -420,7 +429,7 @@ fn serialize_variant(
ty, ty,
fields, fields,
field_names, field_names,
); ));
Ok(quote_arm!(cx, Ok(quote_arm!(cx,
$pat => { $expr } $pat => { $expr }
@@ -468,6 +477,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( fn serialize_tuple_variant(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
@@ -478,7 +516,7 @@ fn serialize_tuple_variant(
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
fields: &[ast::StructField], fields: &[ast::StructField],
field_names: Vec<Ident>, field_names: Vec<Ident>,
) -> P<ast::Expr> { ) -> Result<P<ast::Expr>, Error> {
let variant_ty = builder.ty().tuple() let variant_ty = builder.ty().tuple()
.with_tys( .with_tys(
fields.iter().map(|field| { fields.iter().map(|field| {
@@ -490,15 +528,16 @@ fn serialize_tuple_variant(
) )
.build(); .build();
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor( let (visitor_struct, visitor_impl) = try!(serialize_tuple_struct_visitor(
cx, cx,
builder, builder,
structure_ty.clone(), structure_ty.clone(),
variant_ty, variant_ty,
builder.id("serialize_tuple_variant_elt"), builder.id("serialize_tuple_variant_elt"),
fields.len(), fields,
generics, generics,
); true,
));
let value_expr = builder.expr().tuple() let value_expr = builder.expr().tuple()
.with_exprs( .with_exprs(
@@ -508,7 +547,7 @@ fn serialize_tuple_variant(
) )
.build(); .build();
quote_expr!(cx, { Ok(quote_expr!(cx, {
$visitor_struct $visitor_struct
$visitor_impl $visitor_impl
_serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, Visitor { _serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, Visitor {
@@ -516,7 +555,7 @@ fn serialize_tuple_variant(
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>, _structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
}) })
}) }))
} }
fn serialize_struct_variant( fn serialize_struct_variant(
@@ -614,20 +653,33 @@ fn serialize_tuple_struct_visitor(
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
variant_ty: P<ast::Ty>, variant_ty: P<ast::Ty>,
serializer_method: ast::Ident, serializer_method: ast::Ident,
fields: usize, fields: &[ast::StructField],
generics: &ast::Generics generics: &ast::Generics,
) -> (P<ast::Item>, P<ast::Item>) { is_enum: bool,
let arms: Vec<ast::Arm> = (0 .. fields) ) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
.map(|i| { let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
let expr = builder.expr().method_call(serializer_method)
.id("_serializer") let arms: Vec<_> = fields_with_attrs.iter()
.arg().ref_().tup_field(i).field("value").self_() .enumerate()
.build(); .map(|(i, &(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, quote_arm!(cx,
$i => { $i => {
self.state += 1; self.state += 1;
Ok(Some(try!($expr))) $continue_if_skip
Ok(Some(try!(_serializer.$serializer_method($field_expr))))
} }
) )
}) })
@@ -644,7 +696,9 @@ fn serialize_tuple_struct_visitor(
.strip_bounds() .strip_bounds()
.build(); .build();
( let nfields = fields.len();
Ok((
quote_item!(cx, quote_item!(cx,
struct Visitor $visitor_impl_generics $where_clause { struct Visitor $visitor_impl_generics $where_clause {
state: usize, state: usize,
@@ -658,8 +712,8 @@ fn serialize_tuple_struct_visitor(
for Visitor $visitor_generics for Visitor $visitor_generics
$where_clause { $where_clause {
#[inline] #[inline]
fn visit<S>(&mut self, _serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error> fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
where S: _serde::ser::Serializer where __S: _serde::ser::Serializer
{ {
match self.state { match self.state {
$arms $arms
@@ -669,11 +723,11 @@ fn serialize_tuple_struct_visitor(
#[inline] #[inline]
fn len(&self) -> Option<usize> { fn len(&self) -> Option<usize> {
Some($fields) Some($nfields)
} }
} }
).unwrap(), ).unwrap(),
) ))
} }
fn serialize_struct_visitor( fn serialize_struct_visitor(
@@ -686,28 +740,27 @@ fn serialize_struct_visitor(
generics: &ast::Generics, generics: &ast::Generics,
is_enum: bool, is_enum: bool,
) -> Result<(P<ast::Item>, P<ast::Item>), Error> { ) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
let field_attrs = try!( let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
attr::get_struct_field_attrs(cx, &structure_ty, generics, fields, is_enum)
);
let arms: Vec<ast::Arm> = fields.iter().zip(field_attrs.iter()) let arms: Vec<ast::Arm> = fields_with_attrs.iter()
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field()) .filter(|&&(_, ref attrs)| !attrs.skip_serializing_field())
.enumerate() .enumerate()
.map(|(i, (ref field, ref field_attr))| { .map(|(i, &(field, ref attrs))| {
let name = field.ident.expect("struct has unnamed field"); 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() { let continue_if_skip = attrs.skip_serializing_if()
Some(quote_stmt!(cx, if $expr { continue; })) .map(|path| quote_stmt!(cx, if $path($field_expr) { continue }));
} else {
None
};
let field_expr = match field_attr.serialize_with() { if let Some(path) = attrs.serialize_with() {
Some(expr) => expr.clone(), field_expr = wrap_serialize_with(cx, builder,
None => quote_expr!(cx, &self.value.$name), &structure_ty, generics, &field.ty, path, field_expr)
}; }
let expr = quote_expr!(cx, let expr = quote_expr!(cx,
_serializer.$serializer_method($key_expr, $field_expr) _serializer.$serializer_method($key_expr, $field_expr)
@@ -716,7 +769,7 @@ fn serialize_struct_visitor(
quote_arm!(cx, quote_arm!(cx,
$i => { $i => {
self.state += 1; self.state += 1;
$stmt $continue_if_skip
return Ok(Some(try!($expr))); return Ok(Some(try!($expr)));
} }
) )
@@ -734,16 +787,18 @@ fn serialize_struct_visitor(
.strip_bounds() .strip_bounds()
.build(); .build();
let len = field_attrs.iter() let len = fields_with_attrs.iter()
.filter(|field_attr| !field_attr.skip_serializing_field()) .filter(|&&(_, ref attrs)| !attrs.skip_serializing_field())
.map(|field_attr| { .map(|&(field, ref attrs)| {
match field_attr.skip_serializing_field_if() { let ident = field.ident.expect("struct has unnamed fields");
Some(expr) => { let mut field_expr = quote_expr!(cx, self.value.$ident);
quote_expr!(cx, if $expr { 0 } else { 1 }) if !is_enum {
} field_expr = quote_expr!(cx, &$field_expr);
None => { }
quote_expr!(cx, 1)
} 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)); .fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
@@ -763,8 +818,8 @@ fn serialize_struct_visitor(
for Visitor $visitor_generics for Visitor $visitor_generics
$where_clause { $where_clause {
#[inline] #[inline]
fn visit<S>(&mut self, _serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error> fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
where S: _serde::ser::Serializer, where __S: _serde::ser::Serializer,
{ {
loop { loop {
match self.state { match self.state {
@@ -782,3 +837,46 @@ fn serialize_struct_visitor(
).unwrap(), ).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>,
}
})
}
+4 -3
View File
@@ -1,12 +1,13 @@
[package] [package]
name = "serde_macros" name = "serde_macros"
version = "0.7.4" version = "0.7.7"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" description = "Macros to auto-generate implementations for the serde framework"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
documentation = "https://github.com/serde-rs/serde" documentation = "https://github.com/serde-rs/serde"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[lib] [lib]
name = "serde_macros" name = "serde_macros"
@@ -17,12 +18,12 @@ nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-tes
[dependencies] [dependencies]
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
serde_codegen = { version = "^0.7.4", path = "../serde_codegen", default-features = false, features = ["nightly"] } serde_codegen = { version = "^0.7.7", path = "../serde_codegen", default-features = false, features = ["nightly"] }
[dev-dependencies] [dev-dependencies]
compiletest_rs = "^0.1.1" compiletest_rs = "^0.1.1"
rustc-serialize = "^0.3.16" rustc-serialize = "^0.3.16"
serde = { version = "^0.7.4", path = "../serde" } serde = { version = "^0.7.7", path = "../serde" }
[[test]] [[test]]
name = "test" name = "test"
+4 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_tests" name = "serde_tests"
version = "0.7.1" version = "0.7.6"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
@@ -14,14 +14,14 @@ build = "build.rs"
nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"] nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-testing"]
[build-dependencies] [build-dependencies]
syntex = { version = "^0.32.0" } syntex = { version = "^0.33.0" }
syntex_syntax = { version = "^0.32.0" } syntex_syntax = { version = "^0.33.0" }
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] } serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
[dev-dependencies] [dev-dependencies]
rustc-serialize = "^0.3.16" rustc-serialize = "^0.3.16"
serde = { version = "*", path = "../serde" } serde = { version = "*", path = "../serde" }
syntex = "^0.32.0" syntex = "^0.33.0"
[dependencies] [dependencies]
clippy = { version = "^0.*", optional = true } clippy = { version = "^0.*", optional = true }
+2 -2
View File
@@ -1,9 +1,9 @@
use test::Bencher; use test::Bencher;
use std::error; use std::error;
use std::fmt; use std::fmt;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::Decodable;
use serde; use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::Deserialize;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
+2 -2
View File
@@ -3,10 +3,10 @@ use test::Bencher;
use std::fmt; use std::fmt;
use std::error; use std::error;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::Decodable;
use serde; use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::Deserialize;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
+1
View File
@@ -6,5 +6,6 @@ mod token;
mod test_annotations; mod test_annotations;
mod test_bytes; mod test_bytes;
mod test_de; mod test_de;
mod test_gen;
mod test_macros; mod test_macros;
mod test_ser; mod test_ser;
+14 -3
View File
@@ -237,6 +237,14 @@ impl Default for NotDeserializeStruct {
} }
} }
impl DeserializeWith for NotDeserializeStruct {
fn deserialize_with<D>(_: &mut D) -> Result<Self, D::Error>
where D: Deserializer
{
panic!()
}
}
// Does not implement Deserialize. // Does not implement Deserialize.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum NotDeserializeEnum { Trouble } enum NotDeserializeEnum { Trouble }
@@ -248,13 +256,15 @@ impl MyDefault for NotDeserializeEnum {
} }
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
struct ContainsNotDeserialize<A, B, C: MyDefault> { struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
a: A, a: A,
#[serde(skip_deserializing, default)] #[serde(skip_deserializing, default)]
b: B, b: B,
#[serde(skip_deserializing, default="MyDefault::my_default")] #[serde(deserialize_with="DeserializeWith::deserialize_with", default)]
c: C, c: C,
#[serde(skip_deserializing, default="MyDefault::my_default")]
e: E,
} }
// Tests that a struct field does not need to implement Deserialize if it is // Tests that a struct field does not need to implement Deserialize if it is
@@ -266,7 +276,8 @@ fn test_elt_not_deserialize() {
&ContainsNotDeserialize { &ContainsNotDeserialize {
a: NotDeserializeStruct(123), a: NotDeserializeStruct(123),
b: NotDeserializeStruct(123), b: NotDeserializeStruct(123),
c: NotDeserializeEnum::Trouble, c: NotDeserializeStruct(123),
e: NotDeserializeEnum::Trouble,
}, },
vec![ vec![
Token::StructStart("ContainsNotDeserialize", Some(3)), Token::StructStart("ContainsNotDeserialize", Some(3)),
+28 -3
View File
@@ -2,9 +2,6 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net; use std::net;
use std::path::PathBuf; use std::path::PathBuf;
extern crate serde;
use self::serde::de::{Deserializer, Visitor};
use token::{ use token::{
Error, Error,
Token, Token,
@@ -725,4 +722,32 @@ declare_error_tests! {
], ],
Error::UnexpectedToken(Token::SeqSep), Error::UnexpectedToken(Token::SeqSep),
} }
test_duplicate_field_struct<Struct> {
vec![
Token::MapStart(Some(3)),
Token::MapSep,
Token::Str("a"),
Token::I32(1),
Token::MapSep,
Token::Str("a"),
Token::I32(3),
Token::MapEnd,
],
Error::DuplicateFieldError("a"),
}
test_duplicate_field_enum<Enum> {
vec![
Token::EnumMapStart("Enum", "Map", Some(3)),
Token::EnumMapSep,
Token::Str("a"),
Token::I32(1),
Token::EnumMapSep,
Token::Str("a"),
Token::I32(3),
Token::EnumMapEnd,
],
Error::DuplicateFieldError("a"),
}
} }
+83
View File
@@ -0,0 +1,83 @@
// These just test that serde_codegen is able to produce code that compiles
// successfully when there are a variety of generics and non-(de)serializable
// types involved.
extern crate serde;
use self::serde::ser::{Serialize, Serializer};
use self::serde::de::{Deserialize, Deserializer};
//////////////////////////////////////////////////////////////////////////
#[derive(Serialize, Deserialize)]
struct With<T> {
t: T,
#[serde(serialize_with="ser_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_x", deserialize_with="de_x")]
x: X,
}
#[derive(Serialize, Deserialize)]
struct Bounds<T: Serialize + Deserialize> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
#[derive(Serialize, Deserialize)]
struct NoBounds<T> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
#[derive(Serialize, Deserialize)]
enum EnumWith<T> {
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_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,
);
//////////////////////////////////////////////////////////////////////////
// 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!() }
+9
View File
@@ -410,6 +410,7 @@ pub enum Error {
UnknownFieldError(String), UnknownFieldError(String),
UnknownVariantError(String), UnknownVariantError(String),
MissingFieldError(&'static str), MissingFieldError(&'static str),
DuplicateFieldError(&'static str),
InvalidName(&'static str), InvalidName(&'static str),
InvalidValue(String), InvalidValue(String),
UnexpectedToken(Token<'static>), UnexpectedToken(Token<'static>),
@@ -429,6 +430,10 @@ impl de::Error for Error {
fn end_of_stream() -> Error { Error::EndOfStreamError } fn end_of_stream() -> Error { Error::EndOfStreamError }
fn invalid_value(msg: &str) -> Error {
Error::InvalidValue(msg.to_owned())
}
fn unknown_field(field: &str) -> Error { fn unknown_field(field: &str) -> Error {
Error::UnknownFieldError(field.to_owned()) Error::UnknownFieldError(field.to_owned())
} }
@@ -440,6 +445,10 @@ impl de::Error for Error {
fn missing_field(field: &'static str) -> Error { fn missing_field(field: &'static str) -> Error {
Error::MissingFieldError(field) Error::MissingFieldError(field)
} }
fn duplicate_field(field: &'static str) -> Error {
Error::DuplicateFieldError(field)
}
} }
impl fmt::Display for Error { impl fmt::Display for Error {