Compare commits

...

91 Commits

Author SHA1 Message Date
David Tolnay 7407d71417 Release 1.0.61 2018-05-26 10:38:18 -07:00
David Tolnay 9faa11fd9a Update list of impls to show NonZero* stable 2018-05-26 10:37:08 -07:00
David Tolnay 5310bd87ae Remove unneeded core import
This was previously used by the unstable nonzero impls.

    #[cfg(feature = "unstable")]
    use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
2018-05-26 10:37:06 -07:00
David Tolnay 99091d5925 Merge pull request #1285 from dtolnay/rcdst
Stabilize impls for dynamically sized Rc / Arc
2018-05-26 10:36:52 -07:00
David Tolnay 320a059e4b Stabilize impls for dynamically sized Rc / Arc 2018-05-26 10:06:29 -07:00
David Tolnay 8a596951bf Merge pull request #1284 from serde-rs/boxcstr
Stabilize Deserialize for Box<CStr>
2018-05-26 10:06:14 -07:00
David Tolnay 350406e827 Merge pull request #1283 from serde-rs/dep
Specify serde version required by serde_test
2018-05-26 09:53:47 -07:00
David Tolnay 7ec3cac7d6 Stabilize Deserialize for Box<CStr> 2018-05-26 09:48:50 -07:00
David Tolnay ad47bd132b Specify serde version required by serde_test 2018-05-26 09:42:31 -07:00
David Tolnay 1385aac208 Release 1.0.60 2018-05-25 16:05:01 -07:00
David Tolnay b279ebb244 Merge pull request #1263 from serde-rs/integer128
Add Serde impls for i128 and u128
2018-05-25 16:03:08 -07:00
David Tolnay 039ebc63a1 Merge pull request #1278 from SimonSapin/stable-nonzero
Implement for std::num::NonZero* on Rust 1.28+
2018-05-24 09:47:10 -07:00
Simon Sapin defd8853b1 Implement for std::num::NonZero* on Rust 1.28+
… regardless of the `unstable` feature. Fix #1274.
2018-05-24 18:06:24 +02:00
David Tolnay 7d73089b7c Milder and more general wording for feature requests 2018-05-22 21:30:25 -07:00
David Tolnay 06dcbbbaba Format with rustfmt 0.7.0 2018-05-22 21:27:37 -07:00
David Tolnay ad62a6895c Merge pull request #1275 from serde-rs/nightly
Re-enable testing of nightly proc macro
2018-05-22 21:16:10 -07:00
David Tolnay ced57a9e5f Re-enable testing of nightly proc macro 2018-05-22 21:02:45 -07:00
David Tolnay b5f083e6f4 Update test suite to proc-macro2 0.4 2018-05-21 09:23:00 -07:00
David Tolnay 4de20bd48d Release 1.0.59 2018-05-21 03:51:32 -07:00
David Tolnay 9083cf4b00 Test integer128 impls 2018-05-20 22:17:35 -07:00
David Tolnay c17bc6c49c Add 128-bit deserialization in serde_test 2018-05-20 22:17:35 -07:00
David Tolnay e883dc1bba Include i128 and u128 in forward_to_deserialize_any invocations 2018-05-20 22:17:34 -07:00
David Tolnay 412bedc192 Document conditional compilation of 128-bit methods 2018-05-20 22:17:33 -07:00
David Tolnay 4615e428e8 Document serde_if_integer128 macro 2018-05-20 22:17:32 -07:00
David Tolnay 26fec05611 Add Serde impls for i128 and u128 2018-05-20 22:17:31 -07:00
David Tolnay fdb51cc7dc Add integer128 to Serde traits 2018-05-20 22:17:30 -07:00
David Tolnay 5510f758f8 Add a macro conditional on integer128 support 2018-05-20 22:17:29 -07:00
David Tolnay 922fadf7e3 Merge pull request #1270 from serde-rs/transparent
Transparent attribute to specify that representation is the same as its only field
2018-05-20 22:17:07 -07:00
David Tolnay 6bbc415fdf Resolve conflicts between transparent and proc-macro2 upgrade 2018-05-20 21:57:23 -07:00
David Tolnay b13875dd97 Add compile-fail tests for transparent error messages 2018-05-20 21:55:50 -07:00
David Tolnay ac1b25e91d Improve error messages related to transparent 2018-05-20 21:55:48 -07:00
David Tolnay 1335f85213 Test transparent attribute 2018-05-20 21:55:21 -07:00
David Tolnay 0a4d536253 Implement transparent deserialize 2018-05-20 21:55:20 -07:00
David Tolnay 7dba1e303d Implement transparent serialize 2018-05-20 21:55:19 -07:00
David Tolnay 0ea9d73fdf Validate use of serde(transparent) 2018-05-20 21:55:18 -07:00
David Tolnay a64aaeeb3b Parse serde(transparent) container attribute 2018-05-20 21:55:16 -07:00
David Tolnay 320897679b Merge pull request #1273 from serde-rs/up
Update to proc-macro2 0.4
2018-05-20 21:54:07 -07:00
David Tolnay 3d5141a2f1 Update to proc-macro2 0.4 2018-05-20 20:55:14 -07:00
David Tolnay 656ea96c65 Remove reminders about flatten in a sequence 2018-05-20 12:42:40 -07:00
David Tolnay 5302482596 Simplify deserialize_seq_in_place 2018-05-20 12:40:35 -07:00
David Tolnay 7ada27014d Track field index in internal AST 2018-05-20 12:40:28 -07:00
David Tolnay 4fa2a50f62 Format with rustfmt 0.7.0 2018-05-19 17:33:30 -07:00
David Tolnay 0c5f20c148 Release 1.0.58 2018-05-19 17:30:39 -07:00
David Tolnay aa2bbb4704 Merge pull request #1269 from serde-rs/with
Fix generated code for deserializing untagged newtype variant
2018-05-19 17:30:30 -07:00
David Tolnay 16d1265e17 Fix generated code for deserializing untagged newtype variant 2018-05-19 17:20:14 -07:00
David Tolnay f09320b293 Remove unused methods on FromPrimitive trait 2018-05-19 16:29:25 -07:00
David Tolnay 3b4803115b Release 1.0.57 2018-05-18 23:31:33 -07:00
David Tolnay fa5f0f4541 Remove EnumSet from documentation
These impls were removed in Serde 0.9.6.
2018-05-18 21:26:23 -07:00
David Tolnay 4b7f55bd42 Merge pull request #1265 from serde-rs/nonzero
Remove impls for NonZero<T>
2018-05-18 21:16:03 -07:00
David Tolnay 593bcb087d Remove impls for NonZero<T> 2018-05-18 21:06:14 -07:00
David Tolnay f58000cb41 Release 1.0.56 2018-05-18 12:37:06 -07:00
David Tolnay 01b86d5ce4 Merge pull request #1259 from serde-rs/build
Build script that does nothing
2018-05-18 12:35:13 -07:00
David Tolnay c80f9238d7 Link to i128 announcement 2018-05-18 12:34:36 -07:00
David Tolnay 62850bf832 Disable nightly proc-macro build 2018-05-18 12:24:03 -07:00
David Tolnay 9f114548f4 Revert "Use version_check crate instead of handcrafted version parsing"
This reverts commit 8890061f82.
2018-05-18 11:48:05 -07:00
Oliver Schneider 8890061f82 Use version_check crate instead of handcrafted version parsing 2018-05-18 14:41:40 +02:00
David Tolnay 2c05518810 Build script that does nothing
Eventually we will want a build script that enables Serde impls for i128
and u128. As a first step here is a build script that does nothing to
see whether we can roll this out without breaking anyone's workflow,
without having a supported feature at stake in the event that it needs
to be rolled back.
2018-05-15 14:41:38 -07:00
David Tolnay 4aeb0df88f Add a button to clarify any other type of issue is welcome 2018-05-12 11:27:14 -07:00
David Tolnay 6550231a51 Release 1.0.55 2018-05-12 09:47:43 -07:00
David Tolnay ea0012fc5a Support deserializing bytes as the flattened identifier 2018-05-12 09:44:04 -07:00
David Tolnay d6b62b9417 Release 1.0.54 2018-05-11 23:02:37 -07:00
David Tolnay 2ee347c5a5 Merge pull request #1256 from serde-rs/option
Support flattened untagged Options in struct fields
2018-05-11 23:01:37 -07:00
David Tolnay 4305260174 Support flattened untagged Options in struct fields 2018-05-11 22:14:16 -07:00
David Tolnay 35aae92b56 Remove playground feature
These days serde_derive is in the top 100 crates so it gets picked up
without needing this help from serde.
2018-05-11 01:28:20 -07:00
David Tolnay f3f26796c7 Format with rustfmt 0.6.1 2018-05-10 09:11:19 -07:00
David Tolnay d1460e1f0d Release 1.0.53 2018-05-10 08:44:53 -07:00
David Tolnay dfd81323d5 Cfg away a macro used only by flatten 2018-05-10 08:44:26 -07:00
David Tolnay 368961e961 Support deserializing flattened untagged enum 2018-05-10 08:33:47 -07:00
David Tolnay f9c6f0ab62 Release 1.0.52 2018-05-09 13:01:41 -07:00
David Tolnay b2b36e1764 Accept implicitly borrowed data inside of Option 2018-05-08 12:19:09 -07:00
David Tolnay 4ad140ea70 Improve error for struct deserialized from array that is too short 2018-05-08 12:03:35 -07:00
David Tolnay 67777eb585 Account for skip_serializing_if in tuple struct length 2018-05-08 11:49:37 -07:00
David Tolnay b4e51fcc77 Respect skip_serializing in tuple structs and variants 2018-05-08 11:37:52 -07:00
David Tolnay be7fe2a5eb Introduce bound attribute on enum variants 2018-05-08 11:16:10 -07:00
David Tolnay b4076f4577 Release 1.0.51 2018-05-08 10:07:45 -07:00
David Tolnay c4181f46be Respect variant skip attribute in inferred bounds 2018-05-07 21:30:00 -07:00
David Tolnay 8c0efc3d77 Add a variant skip attribute 2018-05-07 21:27:34 -07:00
David Tolnay 7e3efaf6c5 Improve error when a 'de lifetime parameter already exists 2018-05-07 21:15:44 -07:00
David Tolnay 12fe42ed45 Support empty adjacently tagged enum 2018-05-07 21:02:42 -07:00
David Tolnay 7cd4f49c76 Release 1.0.50 2018-05-07 13:51:32 -07:00
David Tolnay ff9c85d47f Merge pull request #1252 from serde-rs/precondition
Detect deserialize on a struct ending in dynamically sized slice
2018-05-07 13:50:48 -07:00
David Tolnay 0025ef9aba Detect deserialize on a struct ending in dynamically sized slice 2018-05-07 11:52:59 -07:00
David Tolnay 536bdd77a0 Release 1.0.49 2018-05-07 11:51:15 -07:00
David Tolnay 6993b983d2 Merge pull request #1251 from serde-rs/weak
Add impls for Weak
2018-05-07 11:50:35 -07:00
David Tolnay 4bfeb05f22 Prefer Self and associated types in de impls 2018-05-07 11:36:41 -07:00
David Tolnay 4687c1b52b Test Weak deserialize impls 2018-05-07 11:23:18 -07:00
David Tolnay a58abae193 Test Weak serialize impls 2018-05-07 11:23:17 -07:00
David Tolnay 0bc9c729b3 Add impls for Weak 2018-05-07 11:23:16 -07:00
David Tolnay dc921892be Eliminate map_or(None, f) 2018-05-07 11:23:04 -07:00
David Tolnay 62557731c3 Enable pedantic clippy lints in serde_derive 2018-05-07 11:03:09 -07:00
David Tolnay ab62cd3b28 Eliminate loop that does not loop 2018-05-07 10:46:54 -07:00
41 changed files with 2007 additions and 668 deletions
@@ -1,5 +1,5 @@
--- ---
name: Feature request name: Suggestion
about: Share how Serde could support your use case better about: Share how Serde could support your use case better
--- ---
+7
View File
@@ -0,0 +1,7 @@
---
name: Anything else!
about: Whatever is on your mind
---
+3 -7
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.48" # remember to update html_root_url version = "1.0.61" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
@@ -10,7 +10,8 @@ documentation = "https://docs.serde.rs/serde/"
keywords = ["serde", "serialization", "no_std"] keywords = ["serde", "serialization", "no_std"]
categories = ["encoding"] categories = ["encoding"]
readme = "README.md" readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] include = ["Cargo.toml", "build.rs", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
build = "build.rs"
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
@@ -61,8 +62,3 @@ alloc = ["unstable"]
# does not preserve identity and may result in multiple copies of the same data. # does not preserve identity and may result in multiple copies of the same data.
# Be sure that this is what you want before enabling this feature. # Be sure that this is what you want before enabling this feature.
rc = [] rc = []
# Get serde_derive picked up by the Integer 32 playground. Not public API.
#
# http://play.integer32.com/
playground = ["serde_derive"]
+60
View File
@@ -0,0 +1,60 @@
use std::env;
use std::process::Command;
use std::str::{self, FromStr};
fn main() {
let rustc = match env::var_os("RUSTC") {
Some(rustc) => rustc,
None => return,
};
let output = match Command::new(rustc).arg("--version").output() {
Ok(output) => output,
Err(_) => return,
};
let version = match str::from_utf8(&output.stdout) {
Ok(version) => version,
Err(_) => return,
};
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return;
}
let next = match pieces.next() {
Some(next) => next,
None => return,
};
let minor = match u32::from_str(next) {
Ok(minor) => minor,
Err(_) => return,
};
// CString::into_boxed_c_str stabilized in Rust 1.20:
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
if minor >= 20 {
println!("cargo:rustc-cfg=de_boxed_c_str");
}
// From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
// https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
// https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
if minor >= 21 {
println!("cargo:rustc-cfg=de_rc_dst");
}
// 128-bit integers stabilized in Rust 1.26:
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
if minor >= 26 {
println!("cargo:rustc-cfg=integer128");
}
// Non-zero integers stabilized in Rust 1.28:
// https://github.com/rust-lang/rust/pull/50808
if minor >= 28 {
println!("cargo:rustc-cfg=num_nonzero");
}
}
+88 -26
View File
@@ -39,12 +39,10 @@ macro_rules! uint_to {
} }
pub trait FromPrimitive: Sized { pub trait FromPrimitive: Sized {
fn from_isize(n: isize) -> Option<Self>;
fn from_i8(n: i8) -> Option<Self>; fn from_i8(n: i8) -> Option<Self>;
fn from_i16(n: i16) -> Option<Self>; fn from_i16(n: i16) -> Option<Self>;
fn from_i32(n: i32) -> Option<Self>; fn from_i32(n: i32) -> Option<Self>;
fn from_i64(n: i64) -> Option<Self>; fn from_i64(n: i64) -> Option<Self>;
fn from_usize(n: usize) -> Option<Self>;
fn from_u8(n: u8) -> Option<Self>; fn from_u8(n: u8) -> Option<Self>;
fn from_u16(n: u16) -> Option<Self>; fn from_u16(n: u16) -> Option<Self>;
fn from_u32(n: u32) -> Option<Self>; fn from_u32(n: u32) -> Option<Self>;
@@ -54,10 +52,6 @@ pub trait FromPrimitive: Sized {
macro_rules! impl_from_primitive_for_int { macro_rules! impl_from_primitive_for_int {
($t:ident) => { ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline]
fn from_isize(n: isize) -> Option<Self> {
int_to_int!($t, n)
}
#[inline] #[inline]
fn from_i8(n: i8) -> Option<Self> { fn from_i8(n: i8) -> Option<Self> {
int_to_int!($t, n) int_to_int!($t, n)
@@ -75,10 +69,6 @@ macro_rules! impl_from_primitive_for_int {
int_to_int!($t, n) int_to_int!($t, n)
} }
#[inline] #[inline]
fn from_usize(n: usize) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> { fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n) uint_to!($t, n)
} }
@@ -101,10 +91,6 @@ macro_rules! impl_from_primitive_for_int {
macro_rules! impl_from_primitive_for_uint { macro_rules! impl_from_primitive_for_uint {
($t:ident) => { ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline]
fn from_isize(n: isize) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline] #[inline]
fn from_i8(n: i8) -> Option<Self> { fn from_i8(n: i8) -> Option<Self> {
int_to_uint!($t, n) int_to_uint!($t, n)
@@ -122,10 +108,6 @@ macro_rules! impl_from_primitive_for_uint {
int_to_uint!($t, n) int_to_uint!($t, n)
} }
#[inline] #[inline]
fn from_usize(n: usize) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> { fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n) uint_to!($t, n)
} }
@@ -148,10 +130,6 @@ macro_rules! impl_from_primitive_for_uint {
macro_rules! impl_from_primitive_for_float { macro_rules! impl_from_primitive_for_float {
($t:ident) => { ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline]
fn from_isize(n: isize) -> Option<Self> {
Some(n as Self)
}
#[inline] #[inline]
fn from_i8(n: i8) -> Option<Self> { fn from_i8(n: i8) -> Option<Self> {
Some(n as Self) Some(n as Self)
@@ -169,10 +147,6 @@ macro_rules! impl_from_primitive_for_float {
Some(n as Self) Some(n as Self)
} }
#[inline] #[inline]
fn from_usize(n: usize) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> { fn from_u8(n: u8) -> Option<Self> {
Some(n as Self) Some(n as Self)
} }
@@ -204,3 +178,91 @@ impl_from_primitive_for_uint!(u32);
impl_from_primitive_for_uint!(u64); impl_from_primitive_for_uint!(u64);
impl_from_primitive_for_float!(f32); impl_from_primitive_for_float!(f32);
impl_from_primitive_for_float!(f64); impl_from_primitive_for_float!(f64);
serde_if_integer128! {
impl FromPrimitive for i128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as i128)
}
}
impl FromPrimitive for u128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as u128)
}
}
}
+213 -98
View File
@@ -32,7 +32,7 @@ impl<'de> Visitor<'de> for UnitVisitor {
formatter.write_str("unit") formatter.write_str("unit")
} }
fn visit_unit<E>(self) -> Result<(), E> fn visit_unit<E>(self) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -41,7 +41,7 @@ impl<'de> Visitor<'de> for UnitVisitor {
} }
impl<'de> Deserialize<'de> for () { impl<'de> Deserialize<'de> for () {
fn deserialize<D>(deserializer: D) -> Result<(), D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -60,7 +60,7 @@ impl<'de> Visitor<'de> for BoolVisitor {
formatter.write_str("a boolean") formatter.write_str("a boolean")
} }
fn visit_bool<E>(self, v: bool) -> Result<bool, E> fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -69,7 +69,7 @@ impl<'de> Visitor<'de> for BoolVisitor {
} }
impl<'de> Deserialize<'de> for bool { impl<'de> Deserialize<'de> for bool {
fn deserialize<D>(deserializer: D) -> Result<bool, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -110,7 +110,7 @@ macro_rules! impl_deserialize_num {
($ty:ident, $method:ident, $($visit:ident),*) => { ($ty:ident, $method:ident, $($visit:ident),*) => {
impl<'de> Deserialize<'de> for $ty { impl<'de> Deserialize<'de> for $ty {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -166,6 +166,92 @@ impl_deserialize_num!(usize, deserialize_u64, integer);
impl_deserialize_num!(f32, deserialize_f32, integer, float); impl_deserialize_num!(f32, deserialize_f32, integer, float);
impl_deserialize_num!(f64, deserialize_f64, integer, float); impl_deserialize_num!(f64, deserialize_f64, integer, float);
serde_if_integer128! {
impl<'de> Deserialize<'de> for i128 {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PrimitiveVisitor;
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = i128;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("i128")
}
impl_deserialize_num!(integer i128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
if v <= i128::max_value() as u128 {
Ok(v as i128)
} else {
Err(Error::invalid_value(Unexpected::Other("u128"), &self))
}
}
}
deserializer.deserialize_i128(PrimitiveVisitor)
}
}
impl<'de> Deserialize<'de> for u128 {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PrimitiveVisitor;
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = u128;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("u128")
}
impl_deserialize_num!(integer u128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
if v >= 0 {
Ok(v as u128)
} else {
Err(Error::invalid_value(Unexpected::Other("i128"), &self))
}
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
}
deserializer.deserialize_u128(PrimitiveVisitor)
}
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
struct CharVisitor; struct CharVisitor;
@@ -178,7 +264,7 @@ impl<'de> Visitor<'de> for CharVisitor {
} }
#[inline] #[inline]
fn visit_char<E>(self, v: char) -> Result<char, E> fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -186,7 +272,7 @@ impl<'de> Visitor<'de> for CharVisitor {
} }
#[inline] #[inline]
fn visit_str<E>(self, v: &str) -> Result<char, E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -200,7 +286,7 @@ impl<'de> Visitor<'de> for CharVisitor {
impl<'de> Deserialize<'de> for char { impl<'de> Deserialize<'de> for char {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<char, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -223,21 +309,21 @@ impl<'de> Visitor<'de> for StringVisitor {
formatter.write_str("a string") formatter.write_str("a string")
} }
fn visit_str<E>(self, v: &str) -> Result<String, E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
Ok(v.to_owned()) Ok(v.to_owned())
} }
fn visit_string<E>(self, v: String) -> Result<String, E> fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
Ok(v) Ok(v)
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<String, E> fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -247,7 +333,7 @@ impl<'de> Visitor<'de> for StringVisitor {
} }
} }
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<String, E> fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -269,7 +355,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
formatter.write_str("a string") formatter.write_str("a string")
} }
fn visit_str<E>(self, v: &str) -> Result<(), E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -278,7 +364,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
Ok(()) Ok(())
} }
fn visit_string<E>(self, v: String) -> Result<(), E> fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -286,7 +372,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
Ok(()) Ok(())
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<(), E> fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -300,7 +386,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
} }
} }
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<(), E> fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -319,7 +405,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for String { impl<'de> Deserialize<'de> for String {
fn deserialize<D>(deserializer: D) -> Result<String, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -417,7 +503,7 @@ impl<'de> Visitor<'de> for CStringVisitor {
formatter.write_str("byte array") formatter.write_str("byte array")
} }
fn visit_seq<A>(self, mut seq: A) -> Result<CString, A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -431,28 +517,28 @@ impl<'de> Visitor<'de> for CStringVisitor {
CString::new(values).map_err(Error::custom) CString::new(values).map_err(Error::custom)
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<CString, E> fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
CString::new(v).map_err(Error::custom) CString::new(v).map_err(Error::custom)
} }
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<CString, E> fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
CString::new(v).map_err(Error::custom) CString::new(v).map_err(Error::custom)
} }
fn visit_str<E>(self, v: &str) -> Result<CString, E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
CString::new(v).map_err(Error::custom) CString::new(v).map_err(Error::custom)
} }
fn visit_string<E>(self, v: String) -> Result<CString, E> fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -462,7 +548,7 @@ impl<'de> Visitor<'de> for CStringVisitor {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<'de> Deserialize<'de> for CString { impl<'de> Deserialize<'de> for CString {
fn deserialize<D>(deserializer: D) -> Result<CString, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -487,7 +573,7 @@ macro_rules! forwarded_impl {
} }
} }
#[cfg(all(feature = "std", feature = "unstable"))] #[cfg(all(feature = "std", de_boxed_c_str))]
forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str); forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -507,7 +593,7 @@ where
} }
#[inline] #[inline]
fn visit_unit<E>(self) -> Result<Option<T>, E> fn visit_unit<E>(self) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -515,7 +601,7 @@ where
} }
#[inline] #[inline]
fn visit_none<E>(self) -> Result<Option<T>, E> fn visit_none<E>(self) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -523,19 +609,27 @@ where
} }
#[inline] #[inline]
fn visit_some<D>(self, deserializer: D) -> Result<Option<T>, D::Error> fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
T::deserialize(deserializer).map(Some) T::deserialize(deserializer).map(Some)
} }
#[doc(hidden)]
fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
where
D: Deserializer<'de>,
{
Ok(T::deserialize(deserializer).ok())
}
} }
impl<'de, T> Deserialize<'de> for Option<T> impl<'de, T> Deserialize<'de> for Option<T>
where where
T: Deserialize<'de>, T: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Option<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -565,7 +659,7 @@ impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> {
} }
#[inline] #[inline]
fn visit_unit<E>(self) -> Result<PhantomData<T>, E> fn visit_unit<E>(self) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -574,7 +668,7 @@ impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> {
} }
impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> { impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> {
fn deserialize<D>(deserializer: D) -> Result<PhantomData<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -659,7 +753,7 @@ macro_rules! seq_impl {
} }
#[inline] #[inline]
fn visit_seq<A>(mut self, mut $access: A) -> Result<(), A::Error> fn visit_seq<A>(mut self, mut $access: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -771,7 +865,7 @@ impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
} }
#[inline] #[inline]
fn visit_seq<A>(self, _: A) -> Result<[T; 0], A::Error> fn visit_seq<A>(self, _: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -781,7 +875,7 @@ impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
// Does not require T: Deserialize<'de>. // Does not require T: Deserialize<'de>.
impl<'de, T> Deserialize<'de> for [T; 0] { impl<'de, T> Deserialize<'de> for [T; 0] {
fn deserialize<D>(deserializer: D) -> Result<[T; 0], D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -803,7 +897,7 @@ macro_rules! array_impls {
} }
#[inline] #[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<[T; $len], A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -829,7 +923,7 @@ macro_rules! array_impls {
} }
#[inline] #[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -851,7 +945,7 @@ macro_rules! array_impls {
where where
T: Deserialize<'de>, T: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<[T; $len], D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -911,7 +1005,7 @@ macro_rules! tuple_impls {
$( $(
impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) { impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<($($name,)+), D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -928,7 +1022,7 @@ macro_rules! tuple_impls {
#[inline] #[inline]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<($($name,)+), A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -962,7 +1056,7 @@ macro_rules! tuple_impls {
#[inline] #[inline]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -1331,14 +1425,14 @@ impl<'de> Visitor<'de> for PathBufVisitor {
formatter.write_str("path string") formatter.write_str("path string")
} }
fn visit_str<E>(self, v: &str) -> Result<PathBuf, E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
Ok(From::from(v)) Ok(From::from(v))
} }
fn visit_string<E>(self, v: String) -> Result<PathBuf, E> fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1348,7 +1442,7 @@ impl<'de> Visitor<'de> for PathBufVisitor {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<'de> Deserialize<'de> for PathBuf { impl<'de> Deserialize<'de> for PathBuf {
fn deserialize<D>(deserializer: D) -> Result<PathBuf, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1381,7 +1475,7 @@ impl<'de> Visitor<'de> for OsStringVisitor {
} }
#[cfg(unix)] #[cfg(unix)]
fn visit_enum<A>(self, data: A) -> Result<OsString, A::Error> fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where where
A: EnumAccess<'de>, A: EnumAccess<'de>,
{ {
@@ -1396,14 +1490,15 @@ impl<'de> Visitor<'de> for OsStringVisitor {
} }
#[cfg(windows)] #[cfg(windows)]
fn visit_enum<A>(self, data: A) -> Result<OsString, A::Error> fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where where
A: EnumAccess<'de>, A: EnumAccess<'de>,
{ {
use std::os::windows::ffi::OsStringExt; use std::os::windows::ffi::OsStringExt;
match try!(data.variant()) { match try!(data.variant()) {
(OsStringKind::Windows, v) => v.newtype_variant::<Vec<u16>>() (OsStringKind::Windows, v) => v
.newtype_variant::<Vec<u16>>()
.map(|vec| OsString::from_wide(&vec)), .map(|vec| OsString::from_wide(&vec)),
(OsStringKind::Unix, _) => Err(Error::custom( (OsStringKind::Unix, _) => Err(Error::custom(
"cannot deserialize Unix OS string on Windows", "cannot deserialize Unix OS string on Windows",
@@ -1414,7 +1509,7 @@ impl<'de> Visitor<'de> for OsStringVisitor {
#[cfg(all(feature = "std", any(unix, windows)))] #[cfg(all(feature = "std", any(unix, windows)))]
impl<'de> Deserialize<'de> for OsString { impl<'de> Deserialize<'de> for OsString {
fn deserialize<D>(deserializer: D) -> Result<OsString, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1433,7 +1528,7 @@ forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
forwarded_impl!((), Box<str>, String::into_boxed_str); forwarded_impl!((), Box<str>, String::into_boxed_str);
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(not(de_rc_dst), feature = "rc", any(feature = "std", feature = "alloc")))]
forwarded_impl! { forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde. /// This impl requires the [`"rc"`] Cargo feature of Serde.
/// ///
@@ -1445,7 +1540,7 @@ forwarded_impl! {
(T), Arc<T>, Arc::new (T), Arc<T>, Arc::new
} }
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(not(de_rc_dst), feature = "rc", any(feature = "std", feature = "alloc")))]
forwarded_impl! { forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde. /// This impl requires the [`"rc"`] Cargo feature of Serde.
/// ///
@@ -1464,7 +1559,7 @@ where
T::Owned: Deserialize<'de>, T::Owned: Deserialize<'de>,
{ {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<Cow<'a, T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1474,7 +1569,45 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] /// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting
/// `Weak<T>` has a reference count of 0 and cannot be upgraded.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
impl<'de, T: ?Sized> Deserialize<'de> for RcWeak<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
try!(Option::<T>::deserialize(deserializer));
Ok(RcWeak::new())
}
}
/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting
/// `Weak<T>` has a reference count of 0 and cannot be upgraded.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
impl<'de, T: ?Sized> Deserialize<'de> for ArcWeak<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
try!(Option::<T>::deserialize(deserializer));
Ok(ArcWeak::new())
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
macro_rules! box_forwarded_impl { macro_rules! box_forwarded_impl {
( (
$(#[doc = $doc:tt])* $(#[doc = $doc:tt])*
@@ -1495,7 +1628,7 @@ macro_rules! box_forwarded_impl {
}; };
} }
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl! { box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde. /// This impl requires the [`"rc"`] Cargo feature of Serde.
/// ///
@@ -1507,7 +1640,7 @@ box_forwarded_impl! {
Rc Rc
} }
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl! { box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde. /// This impl requires the [`"rc"`] Cargo feature of Serde.
/// ///
@@ -1525,7 +1658,7 @@ impl<'de, T> Deserialize<'de> for Cell<T>
where where
T: Deserialize<'de> + Copy, T: Deserialize<'de> + Copy,
{ {
fn deserialize<D>(deserializer: D) -> Result<Cell<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1567,7 +1700,7 @@ impl<'de> Deserialize<'de> for Duration {
}; };
impl<'de> Deserialize<'de> for Field { impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1580,7 +1713,7 @@ impl<'de> Deserialize<'de> for Duration {
formatter.write_str("`secs` or `nanos`") formatter.write_str("`secs` or `nanos`")
} }
fn visit_str<E>(self, value: &str) -> Result<Field, E> fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1591,7 +1724,7 @@ impl<'de> Deserialize<'de> for Duration {
} }
} }
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E> fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1619,7 +1752,7 @@ impl<'de> Deserialize<'de> for Duration {
formatter.write_str("struct Duration") formatter.write_str("struct Duration")
} }
fn visit_seq<A>(self, mut seq: A) -> Result<Duration, A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -1638,7 +1771,7 @@ impl<'de> Deserialize<'de> for Duration {
Ok(Duration::new(secs, nanos)) Ok(Duration::new(secs, nanos))
} }
fn visit_map<A>(self, mut map: A) -> Result<Duration, A::Error> fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where where
A: MapAccess<'de>, A: MapAccess<'de>,
{ {
@@ -1692,7 +1825,7 @@ impl<'de> Deserialize<'de> for SystemTime {
}; };
impl<'de> Deserialize<'de> for Field { impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1705,7 +1838,7 @@ impl<'de> Deserialize<'de> for SystemTime {
formatter.write_str("`secs_since_epoch` or `nanos_since_epoch`") formatter.write_str("`secs_since_epoch` or `nanos_since_epoch`")
} }
fn visit_str<E>(self, value: &str) -> Result<Field, E> fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1716,7 +1849,7 @@ impl<'de> Deserialize<'de> for SystemTime {
} }
} }
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E> fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1744,7 +1877,7 @@ impl<'de> Deserialize<'de> for SystemTime {
formatter.write_str("struct SystemTime") formatter.write_str("struct SystemTime")
} }
fn visit_seq<A>(self, mut seq: A) -> Result<Duration, A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -1763,7 +1896,7 @@ impl<'de> Deserialize<'de> for SystemTime {
Ok(Duration::new(secs, nanos)) Ok(Duration::new(secs, nanos))
} }
fn visit_map<A>(self, mut map: A) -> Result<Duration, A::Error> fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where where
A: MapAccess<'de>, A: MapAccess<'de>,
{ {
@@ -1836,7 +1969,7 @@ where
}; };
impl<'de> Deserialize<'de> for Field { impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -1849,7 +1982,7 @@ where
formatter.write_str("`start` or `end`") formatter.write_str("`start` or `end`")
} }
fn visit_str<E>(self, value: &str) -> Result<Field, E> fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1860,7 +1993,7 @@ where
} }
} }
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E> fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -1893,7 +2026,7 @@ where
formatter.write_str("struct Range") formatter.write_str("struct Range")
} }
fn visit_seq<A>(self, mut seq: A) -> Result<ops::Range<Idx>, A::Error> fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
@@ -1912,7 +2045,7 @@ where
Ok(start..end) Ok(start..end)
} }
fn visit_map<A>(self, mut map: A) -> Result<ops::Range<Idx>, A::Error> fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where where
A: MapAccess<'de>, A: MapAccess<'de>,
{ {
@@ -1959,35 +2092,17 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)]
impl<'de, T> Deserialize<'de> for NonZero<T>
where
T: Deserialize<'de> + Zeroable,
{
fn deserialize<D>(deserializer: D) -> Result<NonZero<T>, D::Error>
where
D: Deserializer<'de>,
{
let value = try!(Deserialize::deserialize(deserializer));
match NonZero::new(value) {
Some(nonzero) => Ok(nonzero),
None => Err(Error::custom("expected a non-zero value")),
}
}
}
macro_rules! nonzero_integers { macro_rules! nonzero_integers {
( $( $T: ty, )+ ) => { ( $( $T: ident, )+ ) => {
$( $(
#[cfg(feature = "unstable")] #[cfg(num_nonzero)]
impl<'de> Deserialize<'de> for $T { impl<'de> Deserialize<'de> for num::$T {
fn deserialize<D>(deserializer: D) -> Result<$T, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let value = try!(Deserialize::deserialize(deserializer)); let value = try!(Deserialize::deserialize(deserializer));
match <$T>::new(value) { match <num::$T>::new(value) {
Some(nonzero) => Ok(nonzero), Some(nonzero) => Ok(nonzero),
None => Err(Error::custom("expected a non-zero value")), None => Err(Error::custom("expected a non-zero value")),
} }
@@ -2014,7 +2129,7 @@ where
T: Deserialize<'de>, T: Deserialize<'de>,
E: Deserialize<'de>, E: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Result<T, E>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -2029,7 +2144,7 @@ where
impl<'de> Deserialize<'de> for Field { impl<'de> Deserialize<'de> for Field {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -2042,7 +2157,7 @@ where
formatter.write_str("`Ok` or `Err`") formatter.write_str("`Ok` or `Err`")
} }
fn visit_u32<E>(self, value: u32) -> Result<Field, E> fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -2056,7 +2171,7 @@ where
} }
} }
fn visit_str<E>(self, value: &str) -> Result<Field, E> fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -2067,7 +2182,7 @@ where
} }
} }
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E> fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where where
E: Error, E: Error,
{ {
@@ -2101,7 +2216,7 @@ where
formatter.write_str("enum Result") formatter.write_str("enum Result")
} }
fn visit_enum<A>(self, data: A) -> Result<Result<T, E>, A::Error> fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where where
A: EnumAccess<'de>, A: EnumAccess<'de>,
{ {
@@ -2125,7 +2240,7 @@ impl<'de, T> Deserialize<'de> for Wrapping<T>
where where
T: Deserialize<'de>, T: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
+72 -21
View File
@@ -52,8 +52,8 @@
//! //!
//! - **Primitive types**: //! - **Primitive types**:
//! - bool //! - bool
//! - i8, i16, i32, i64, isize //! - i8, i16, i32, i64, i128, isize
//! - u8, u16, u32, u64, usize //! - u8, u16, u32, u64, u128, usize
//! - f32, f64 //! - f32, f64
//! - char //! - char
//! - **Compound types**: //! - **Compound types**:
@@ -84,7 +84,6 @@
//! - LinkedList\<T\> //! - LinkedList\<T\>
//! - VecDeque\<T\> //! - VecDeque\<T\>
//! - Vec\<T\> //! - Vec\<T\>
//! - EnumSet\<T\> (unstable)
//! - **Zero-copy types**: //! - **Zero-copy types**:
//! - &str //! - &str
//! - &[u8] //! - &[u8]
@@ -98,8 +97,7 @@
//! - Path //! - Path
//! - PathBuf //! - PathBuf
//! - Range\<T\> //! - Range\<T\>
//! - NonZero\<T\> (unstable, deprecated) //! - num::NonZero*
//! - num::NonZero* (unstable)
//! - **Net types**: //! - **Net types**:
//! - IpAddr //! - IpAddr
//! - Ipv4Addr //! - Ipv4Addr
@@ -759,7 +757,7 @@ where
/// Serde. /// Serde.
/// ///
/// The role of this trait is to define the deserialization half of the Serde /// The role of this trait is to define the deserialization half of the Serde
/// data model, which is a way to categorize every Rust data type into one of 27 /// data model, which is a way to categorize every Rust data type into one of 29
/// possible types. Each method of the `Serializer` trait corresponds to one of /// possible types. Each method of the `Serializer` trait corresponds to one of
/// the types of the data model. /// the types of the data model.
/// ///
@@ -769,10 +767,10 @@ where
/// ///
/// The types that make up the Serde data model are: /// The types that make up the Serde data model are:
/// ///
/// - **12 primitive types** /// - **14 primitive types**
/// - bool /// - bool
/// - i8, i16, i32, i64 /// - i8, i16, i32, i64, i128
/// - u8, u16, u32, u64 /// - u8, u16, u32, u64, u128
/// - f32, f64 /// - f32, f64
/// - char /// - char
/// - **string** /// - **string**
@@ -886,6 +884,20 @@ pub trait Deserializer<'de>: Sized {
where where
V: Visitor<'de>; V: Visitor<'de>;
serde_if_integer128! {
/// Hint that the `Deserialize` type is expecting an `i128` value.
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default behavior unconditionally returns an error.
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>
{
let _ = visitor;
Err(Error::custom("i128 is not supported"))
}
}
/// Hint that the `Deserialize` type is expecting a `u8` value. /// Hint that the `Deserialize` type is expecting a `u8` value.
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where where
@@ -906,6 +918,20 @@ pub trait Deserializer<'de>: Sized {
where where
V: Visitor<'de>; V: Visitor<'de>;
serde_if_integer128! {
/// Hint that the `Deserialize` type is expecting an `u128` value.
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default behavior unconditionally returns an error.
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>
{
let _ = visitor;
Err(Error::custom("u128 is not supported"))
}
}
/// Hint that the `Deserialize` type is expecting a `f32` value. /// Hint that the `Deserialize` type is expecting a `f32` value.
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where where
@@ -1132,18 +1158,6 @@ pub trait Deserializer<'de>: Sized {
fn is_human_readable(&self) -> bool { fn is_human_readable(&self) -> bool {
true true
} }
// Not public API.
#[doc(hidden)]
fn private_deserialize_internally_tagged_enum<V>(
self,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1264,6 +1278,20 @@ pub trait Visitor<'de>: Sized {
Err(Error::invalid_type(Unexpected::Signed(v), &self)) Err(Error::invalid_type(Unexpected::Signed(v), &self))
} }
serde_if_integer128! {
/// The input contains a `i128`.
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default implementation fails with a type error.
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
let _ = v;
Err(Error::invalid_type(Unexpected::Other("i128"), &self))
}
}
/// The input contains a `u8`. /// The input contains a `u8`.
/// ///
/// The default implementation forwards to [`visit_u64`]. /// The default implementation forwards to [`visit_u64`].
@@ -1310,6 +1338,20 @@ pub trait Visitor<'de>: Sized {
Err(Error::invalid_type(Unexpected::Unsigned(v), &self)) Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
} }
serde_if_integer128! {
/// The input contains a `u128`.
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default implementation fails with a type error.
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
let _ = v;
Err(Error::invalid_type(Unexpected::Other("u128"), &self))
}
}
/// The input contains an `f32`. /// The input contains an `f32`.
/// ///
/// The default implementation forwards to [`visit_f64`]. /// The default implementation forwards to [`visit_f64`].
@@ -1541,6 +1583,15 @@ pub trait Visitor<'de>: Sized {
let _ = data; let _ = data;
Err(Error::invalid_type(Unexpected::Enum, &self)) Err(Error::invalid_type(Unexpected::Enum, &self))
} }
// Used when deserializing a flattened Option field. Not public API.
#[doc(hidden)]
fn __private_visit_untagged_option<D>(self, _: D) -> Result<Self::Value, ()>
where
D: Deserializer<'de>,
{
Err(())
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
+39 -39
View File
@@ -136,9 +136,9 @@ where
type Error = E; type Error = E;
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf unit unit_struct newtype_struct seq tuple tuple_struct map bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct
struct enum identifier ignored_any map struct enum identifier ignored_any
} }
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -189,9 +189,9 @@ macro_rules! primitive_deserializer {
type Error = E; type Error = E;
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str
byte_buf option unit unit_struct newtype_struct seq tuple string bytes byte_buf option unit unit_struct newtype_struct seq
tuple_struct map struct enum identifier ignored_any tuple tuple_struct map struct enum identifier ignored_any
} }
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -246,9 +246,9 @@ where
type Error = E; type Error = E;
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any tuple_struct map struct identifier ignored_any
} }
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -339,9 +339,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any tuple_struct map struct identifier ignored_any
} }
} }
@@ -408,9 +408,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any tuple_struct map struct identifier ignored_any
} }
} }
@@ -483,9 +483,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any tuple_struct map struct identifier ignored_any
} }
} }
@@ -562,9 +562,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any tuple_struct map struct identifier ignored_any
} }
} }
@@ -618,9 +618,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct identifier ignored_any enum tuple_struct map struct identifier ignored_any enum
} }
} }
@@ -688,9 +688,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -803,9 +803,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -917,9 +917,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct tuple_struct map struct bytes byte_buf option unit unit_struct newtype_struct tuple_struct map
enum identifier ignored_any struct enum identifier ignored_any
} }
} }
@@ -1059,9 +1059,9 @@ where
type Error = E; type Error = E;
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct tuple_struct map struct bytes byte_buf option unit unit_struct newtype_struct tuple_struct map
enum identifier ignored_any struct enum identifier ignored_any
} }
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -1207,9 +1207,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
+86
View File
@@ -0,0 +1,86 @@
/// Conditional compilation depending on whether Serde is built with support for
/// 128-bit integers.
///
/// Data formats that wish to support Rust compiler versions older than 1.26 may
/// place the i128 / u128 methods of their Serializer and Deserializer behind
/// this macro.
///
/// Data formats that require a minimum Rust compiler version of at least 1.26
/// do not need to bother with this macro and may assume support for 128-bit
/// integers.
///
/// ```rust
/// #[macro_use]
/// extern crate serde;
///
/// use serde::Serializer;
/// # use serde::private::ser::Error;
/// #
/// # struct MySerializer;
///
/// impl Serializer for MySerializer {
/// type Ok = ();
/// type Error = Error;
///
/// fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
/// /* ... */
/// # unimplemented!()
/// }
///
/// /* ... */
///
/// serde_if_integer128! {
/// fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
/// /* ... */
/// # unimplemented!()
/// }
///
/// fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
/// /* ... */
/// # unimplemented!()
/// }
/// }
/// #
/// # __serialize_unimplemented! {
/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some
/// # unit unit_struct unit_variant newtype_struct newtype_variant seq
/// # tuple tuple_struct tuple_variant map struct struct_variant
/// # }
/// }
/// #
/// # fn main() {}
/// ```
///
/// When Serde is built with support for 128-bit integers, this macro expands
/// transparently into just the input tokens.
///
/// ```rust
/// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => {
/// $($tt)*
/// };
/// }
/// ```
///
/// When built without support for 128-bit integers, this macro expands to
/// nothing.
///
/// ```rust
/// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => {};
/// }
/// ```
#[cfg(integer128)]
#[macro_export]
macro_rules! serde_if_integer128 {
($($tt:tt)*) => {
$($tt)*
};
}
#[cfg(not(integer128))]
#[macro_export]
#[doc(hidden)]
macro_rules! serde_if_integer128 {
($($tt:tt)*) => {};
}
+10 -17
View File
@@ -79,14 +79,14 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.48")] #![doc(html_root_url = "https://docs.rs/serde/1.0.61")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue: // discussion of these features please refer to this issue:
// //
// https://github.com/serde-rs/serde/issues/812 // https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))] #![cfg_attr(feature = "unstable", feature(specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
@@ -130,9 +130,6 @@
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;
/// A facade around all the types we need from the `std`, `core`, and `alloc` /// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every /// crates. This avoids elaborate import wrangling having to happen in every
/// module. /// module.
@@ -144,7 +141,7 @@ mod lib {
pub use std::*; pub use std::*;
} }
pub use self::core::{cmp, iter, mem, ops, slice, str}; pub use self::core::{cmp, iter, mem, num, ops, slice, str};
pub use self::core::{f32, f64}; pub use self::core::{f32, f64};
pub use self::core::{i16, i32, i64, i8, isize}; pub use self::core::{i16, i32, i64, i8, isize};
pub use self::core::{u16, u32, u64, u8, usize}; pub use self::core::{u16, u32, u64, u8, usize};
@@ -179,14 +176,14 @@ mod lib {
pub use std::boxed::Box; pub use std::boxed::Box;
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::rc::Rc; pub use alloc::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "std"))] #[cfg(all(feature = "rc", feature = "std"))]
pub use std::rc::Rc; pub use std::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::arc::Arc; pub use alloc::arc::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "rc", feature = "std"))] #[cfg(all(feature = "rc", feature = "std"))]
pub use std::sync::Arc; pub use std::sync::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
@@ -212,13 +209,6 @@ mod lib {
pub use std::sync::{Mutex, RwLock}; pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::time::{Duration, SystemTime, UNIX_EPOCH}; pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(feature = "unstable")]
#[allow(deprecated)]
pub use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "unstable")]
pub use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -226,6 +216,9 @@ mod lib {
#[macro_use] #[macro_use]
mod macros; mod macros;
#[macro_use]
mod integer128;
pub mod de; pub mod de;
pub mod ser; pub mod ser;
+17 -7
View File
@@ -46,8 +46,8 @@
/// } /// }
/// # /// #
/// # forward_to_deserialize_any! { /// # forward_to_deserialize_any! {
/// # i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes /// # i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
/// # byte_buf option unit unit_struct newtype_struct seq tuple /// # bytes byte_buf option unit unit_struct newtype_struct seq tuple
/// # tuple_struct map struct enum identifier ignored_any /// # tuple_struct map struct enum identifier ignored_any
/// # } /// # }
/// # } /// # }
@@ -80,8 +80,8 @@
/// } /// }
/// ///
/// forward_to_deserialize_any! { /// forward_to_deserialize_any! {
/// bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes /// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
/// byte_buf option unit unit_struct newtype_struct seq tuple /// bytes byte_buf option unit unit_struct newtype_struct seq tuple
/// tuple_struct map struct enum identifier ignored_any /// tuple_struct map struct enum identifier ignored_any
/// } /// }
/// } /// }
@@ -116,9 +116,9 @@
/// # /// #
/// forward_to_deserialize_any! { /// forward_to_deserialize_any! {
/// <W: Visitor<'q>> /// <W: Visitor<'q>>
/// bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes /// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
/// byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct /// bytes byte_buf option unit unit_struct newtype_struct seq tuple
/// map struct enum identifier ignored_any /// tuple_struct map struct enum identifier ignored_any
/// } /// }
/// # } /// # }
/// # /// #
@@ -174,6 +174,11 @@ macro_rules! forward_to_deserialize_any_helper {
(i64<$l:tt, $v:ident>) => { (i64<$l:tt, $v:ident>) => {
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()} forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
}; };
(i128<$l:tt, $v:ident>) => {
serde_if_integer128! {
forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()}
}
};
(u8<$l:tt, $v:ident>) => { (u8<$l:tt, $v:ident>) => {
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()} forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
}; };
@@ -186,6 +191,11 @@ macro_rules! forward_to_deserialize_any_helper {
(u64<$l:tt, $v:ident>) => { (u64<$l:tt, $v:ident>) => {
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()} forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
}; };
(u128<$l:tt, $v:ident>) => {
serde_if_integer128! {
forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()}
}
};
(f32<$l:tt, $v:ident>) => { (f32<$l:tt, $v:ident>) => {
forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()} forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()}
}; };
+104 -52
View File
@@ -50,9 +50,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf unit unit_struct newtype_struct seq tuple tuple_struct map bytes byte_buf unit unit_struct newtype_struct seq tuple
struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -276,6 +276,8 @@ mod content {
match *self { match *self {
Content::Str(x) => Some(x), Content::Str(x) => Some(x),
Content::String(ref x) => Some(x), Content::String(ref x) => Some(x),
Content::Bytes(x) => str::from_utf8(x).ok(),
Content::ByteBuf(ref x) => str::from_utf8(x).ok(),
_ => None, _ => None,
} }
} }
@@ -1423,6 +1425,8 @@ mod content {
match self.content { match self.content {
Content::String(v) => visitor.visit_string(v), Content::String(v) => visitor.visit_string(v),
Content::Str(v) => visitor.visit_borrowed_str(v), Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(v) => visitor.visit_byte_buf(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
_ => Err(self.invalid_type(&visitor)), _ => Err(self.invalid_type(&visitor)),
} }
} }
@@ -1614,8 +1618,8 @@ mod content {
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -1712,8 +1716,8 @@ mod content {
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -2123,6 +2127,8 @@ mod content {
match *self.content { match *self.content {
Content::String(ref v) => visitor.visit_str(v), Content::String(ref v) => visitor.visit_str(v),
Content::Str(v) => visitor.visit_borrowed_str(v), Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(ref v) => visitor.visit_bytes(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
_ => Err(self.invalid_type(&visitor)), _ => Err(self.invalid_type(&visitor)),
} }
} }
@@ -2300,8 +2306,8 @@ mod content {
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -2317,7 +2323,8 @@ mod content {
T: de::DeserializeSeed<'de>, T: de::DeserializeSeed<'de>,
{ {
match self.iter.next() { match self.iter.next() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)) Some(value) => seed
.deserialize(ContentRefDeserializer::new(value))
.map(Some), .map(Some),
None => Ok(None), None => Ok(None),
} }
@@ -2399,8 +2406,8 @@ mod content {
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -2571,9 +2578,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -2610,9 +2617,9 @@ where
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
@@ -2640,6 +2647,30 @@ pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub PhantomData<E>, pub PhantomData<E>,
); );
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
where
E: Error,
{
fn deserialize_other<V>() -> Result<V, E> {
Err(Error::custom("can only flatten structs and maps"))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! forward_to_deserialize_other {
($($func:ident ( $($arg:ty),* ))*) => {
$(
fn $func<V>(self, $(_: $arg,)* _visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Self::deserialize_other()
}
)*
}
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E> impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
where where
@@ -2647,11 +2678,15 @@ where
{ {
type Error = E; type Error = E;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
Err(Error::custom("can only flatten structs and maps")) visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
} }
fn deserialize_enum<V>( fn deserialize_enum<V>(
@@ -2710,24 +2745,40 @@ where
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
forward_to_deserialize_any! { fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct seq tuple tuple_struct identifier
ignored_any
}
fn private_deserialize_internally_tagged_enum<V>(
self,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatInternallyTaggedAccess { match visitor.__private_visit_untagged_option(self) {
iter: self.0.iter_mut(), Ok(value) => Ok(value),
pending: None, Err(()) => Self::deserialize_other(),
_marker: PhantomData, }
}) }
forward_to_deserialize_other! {
deserialize_bool()
deserialize_i8()
deserialize_i16()
deserialize_i32()
deserialize_i64()
deserialize_u8()
deserialize_u16()
deserialize_u32()
deserialize_u64()
deserialize_f32()
deserialize_f64()
deserialize_char()
deserialize_str()
deserialize_string()
deserialize_bytes()
deserialize_byte_buf()
deserialize_unit()
deserialize_unit_struct(&'static str)
deserialize_seq()
deserialize_tuple(usize)
deserialize_tuple_struct(&'static str, usize)
deserialize_identifier()
deserialize_ignored_any()
} }
} }
@@ -2771,14 +2822,13 @@ where
// about. In case we do not know which fields we want, we take them all. // about. In case we do not know which fields we want, we take them all.
let use_item = match *item { let use_item = match *item {
None => false, None => false,
Some((ref c, _)) => { Some((ref c, _)) => c.as_str().map_or(self.fields.is_none(), |key| {
c.as_str() match self.fields {
.map_or(self.fields.is_none(), |key| match self.fields { None => true,
None => true, Some(fields) if fields.contains(&key) => true,
Some(fields) if fields.contains(&key) => true, _ => false,
_ => false, }
}) }),
}
}; };
if use_item { if use_item {
@@ -2819,16 +2869,18 @@ where
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
while let Some(item) = self.iter.next() { match self.iter.next() {
// Do not take(), instead borrow this entry. The internally tagged Some(item) => {
// enum does its own buffering so we can't tell whether this entry // Do not take(), instead borrow this entry. The internally tagged
// is going to be consumed. Borrowing here leaves the entry // enum does its own buffering so we can't tell whether this entry
// available for later flattened fields. // is going to be consumed. Borrowing here leaves the entry
let (ref key, ref content) = *item.as_ref().unwrap(); // available for later flattened fields.
self.pending = Some(content); let (ref key, ref content) = *item.as_ref().unwrap();
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); self.pending = Some(content);
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
}
None => Ok(None),
} }
Ok(None)
} }
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
+5 -4
View File
@@ -947,7 +947,8 @@ mod content {
where where
T: Serialize, T: Serialize,
{ {
let key = self.key let key = self
.key
.take() .take()
.expect("serialize_value called before serialize_key"); .expect("serialize_value called before serialize_key");
let value = try!(value.serialize(ContentSerializer::<E>::new())); let value = try!(value.serialize(ContentSerializer::<E>::new()));
@@ -1122,14 +1123,14 @@ where
} }
fn serialize_none(self) -> Result<Self::Ok, Self::Error> { fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Optional)) Ok(())
} }
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error> fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where where
T: Serialize, T: Serialize,
{ {
Err(self.bad_type(Unsupported::Optional)) value.serialize(self)
} }
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+34 -8
View File
@@ -44,6 +44,11 @@ primitive_impl!(f32, serialize_f32);
primitive_impl!(f64, serialize_f64); primitive_impl!(f64, serialize_f64);
primitive_impl!(char, serialize_char); primitive_impl!(char, serialize_char);
serde_if_integer128! {
primitive_impl!(i128, serialize_i128);
primitive_impl!(u128, serialize_u128);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl Serialize for str { impl Serialize for str {
@@ -374,25 +379,45 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")] /// This impl requires the [`"rc"`] Cargo feature of Serde.
#[allow(deprecated)] ///
impl<T> Serialize for NonZero<T> /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
impl<T: ?Sized> Serialize for RcWeak<T>
where where
T: Serialize + Zeroable + Clone, T: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
{ {
self.clone().get().serialize(serializer) self.upgrade().serialize(serializer)
} }
} }
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
impl<T: ?Sized> Serialize for ArcWeak<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.upgrade().serialize(serializer)
}
}
////////////////////////////////////////////////////////////////////////////////
macro_rules! nonzero_integers { macro_rules! nonzero_integers {
( $( $T: ident, )+ ) => { ( $( $T: ident, )+ ) => {
$( $(
#[cfg(feature = "unstable")] #[cfg(num_nonzero)]
impl Serialize for $T { impl Serialize for num::$T {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
@@ -515,7 +540,8 @@ impl Serialize for SystemTime {
S: Serializer, S: Serializer,
{ {
use super::SerializeStruct; use super::SerializeStruct;
let duration_since_epoch = self.duration_since(UNIX_EPOCH) let duration_since_epoch = self
.duration_since(UNIX_EPOCH)
.expect("SystemTime must be later than UNIX_EPOCH"); .expect("SystemTime must be later than UNIX_EPOCH");
let mut state = try!(serializer.serialize_struct("SystemTime", 2)); let mut state = try!(serializer.serialize_struct("SystemTime", 2));
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs())); try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
+69 -9
View File
@@ -48,8 +48,8 @@
//! //!
//! - **Primitive types**: //! - **Primitive types**:
//! - bool //! - bool
//! - i8, i16, i32, i64, isize //! - i8, i16, i32, i64, i128, isize
//! - u8, u16, u32, u64, usize //! - u8, u16, u32, u64, u128, usize
//! - f32, f64 //! - f32, f64
//! - char //! - char
//! - str //! - str
@@ -81,7 +81,6 @@
//! - LinkedList\<T\> //! - LinkedList\<T\>
//! - VecDeque\<T\> //! - VecDeque\<T\>
//! - Vec\<T\> //! - Vec\<T\>
//! - EnumSet\<T\> (unstable)
//! - **FFI types**: //! - **FFI types**:
//! - CStr //! - CStr
//! - CString //! - CString
@@ -93,8 +92,7 @@
//! - Path //! - Path
//! - PathBuf //! - PathBuf
//! - Range\<T\> //! - Range\<T\>
//! - NonZero\<T\> (unstable, deprecated) //! - num::NonZero*
//! - num::NonZero* (unstable)
//! - **Net types**: //! - **Net types**:
//! - IpAddr //! - IpAddr
//! - Ipv4Addr //! - Ipv4Addr
@@ -247,7 +245,7 @@ pub trait Serialize {
/// A **data format** that can serialize any data structure supported by Serde. /// A **data format** that can serialize any data structure supported by Serde.
/// ///
/// The role of this trait is to define the serialization half of the Serde data /// The role of this trait is to define the serialization half of the Serde data
/// model, which is a way to categorize every Rust data structure into one of 27 /// model, which is a way to categorize every Rust data structure into one of 29
/// possible types. Each method of the `Serializer` trait corresponds to one of /// possible types. Each method of the `Serializer` trait corresponds to one of
/// the types of the data model. /// the types of the data model.
/// ///
@@ -256,10 +254,10 @@ pub trait Serialize {
/// ///
/// The types that make up the Serde data model are: /// The types that make up the Serde data model are:
/// ///
/// - **12 primitive types** /// - **14 primitive types**
/// - bool /// - bool
/// - i8, i16, i32, i64 /// - i8, i16, i32, i64, i128
/// - u8, u16, u32, u64 /// - u8, u16, u32, u64, u128
/// - f32, f64 /// - f32, f64
/// - char /// - char
/// - **string** /// - **string**
@@ -494,6 +492,37 @@ pub trait Serializer: Sized {
/// ``` /// ```
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>; fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>;
serde_if_integer128! {
/// Serialize an `i128` value.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde;
/// #
/// # use serde::Serializer;
/// #
/// # __private_serialize!();
/// #
/// impl Serialize for i128 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where
/// S: Serializer,
/// {
/// serializer.serialize_i128(*self)
/// }
/// }
/// #
/// # fn main() {}
/// ```
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default behavior unconditionally returns an error.
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
let _ = v;
Err(Error::custom("i128 is not supported"))
}
}
/// Serialize a `u8` value. /// Serialize a `u8` value.
/// ///
/// If the format does not differentiate between `u8` and `u64`, a /// If the format does not differentiate between `u8` and `u64`, a
@@ -598,6 +627,37 @@ pub trait Serializer: Sized {
/// ``` /// ```
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>; fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>;
serde_if_integer128! {
/// Serialize a `u128` value.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde;
/// #
/// # use serde::Serializer;
/// #
/// # __private_serialize!();
/// #
/// impl Serialize for u128 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where
/// S: Serializer,
/// {
/// serializer.serialize_u128(*self)
/// }
/// }
/// #
/// # fn main() {}
/// ```
///
/// This method is available only on Rust compiler versions >=1.26. The
/// default behavior unconditionally returns an error.
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
let _ = v;
Err(Error::custom("u128 is not supported"))
}
}
/// Serialize an `f32` value. /// Serialize an `f32` value.
/// ///
/// If the format does not differentiate between `f32` and `f64`, a /// If the format does not differentiate between `f32` and `f64`, a
+4 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.48" # remember to update html_root_url version = "1.0.61" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -23,9 +23,9 @@ name = "serde_derive"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "0.3" proc-macro2 = "0.4"
quote = "0.5.2" quote = "0.6"
syn = { version = "0.13", features = ["visit"] } syn = { version = "0.14", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+42 -13
View File
@@ -55,7 +55,8 @@ pub fn with_where_predicates_from_fields(
generics: &syn::Generics, generics: &syn::Generics,
from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>, from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics { ) -> syn::Generics {
let predicates = cont.data let predicates = cont
.data
.all_fields() .all_fields()
.flat_map(|field| from_field(&field.attrs)) .flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec()); .flat_map(|predicates| predicates.to_vec());
@@ -65,6 +66,28 @@ pub fn with_where_predicates_from_fields(
generics generics
} }
pub fn with_where_predicates_from_variants(
cont: &Container,
generics: &syn::Generics,
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => {
return generics.clone();
}
};
let predicates = variants
.iter()
.flat_map(|variant| from_variant(&variant.attrs))
.flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone();
generics.make_where_clause().predicates.extend(predicates);
generics
}
// Puts the given bound on any generic type parameters that are used in fields // Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true. // for which filter returns true.
// //
@@ -117,9 +140,9 @@ pub fn with_bound(
} }
} }
if path.leading_colon.is_none() && path.segments.len() == 1 { if path.leading_colon.is_none() && path.segments.len() == 1 {
let id = path.segments[0].ident; let id = &path.segments[0].ident;
if self.all_type_params.contains(&id) { if self.all_type_params.contains(id) {
self.relevant_type_params.insert(id); self.relevant_type_params.insert(id.clone());
} }
} }
visit::visit_path(self, path); visit::visit_path(self, path);
@@ -134,7 +157,10 @@ pub fn with_bound(
fn visit_macro(&mut self, _mac: &'ast syn::Macro) {} fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
} }
let all_type_params = generics.type_params().map(|param| param.ident).collect(); let all_type_params = generics
.type_params()
.map(|param| param.ident.clone())
.collect();
let mut visitor = FindTyParams { let mut visitor = FindTyParams {
all_type_params: all_type_params, all_type_params: all_type_params,
@@ -162,7 +188,7 @@ pub fn with_bound(
let associated_type_usage = visitor.associated_type_usage; let associated_type_usage = visitor.associated_type_usage;
let new_predicates = generics let new_predicates = generics
.type_params() .type_params()
.map(|param| param.ident) .map(|param| param.ident.clone())
.filter(|id| relevant_type_params.contains(id)) .filter(|id| relevant_type_params.contains(id))
.map(|id| syn::TypePath { .map(|id| syn::TypePath {
qself: None, qself: None,
@@ -224,7 +250,7 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
let bound = syn::Lifetime::new(lifetime, Span::call_site()); let bound = syn::Lifetime::new(lifetime, Span::call_site());
let def = syn::LifetimeDef { let def = syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: bound, lifetime: bound.clone(),
colon_token: None, colon_token: None,
bounds: Punctuated::new(), bounds: Punctuated::new(),
}; };
@@ -234,10 +260,12 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
.chain(generics.params.iter().cloned().map(|mut param| { .chain(generics.params.iter().cloned().map(|mut param| {
match param { match param {
syn::GenericParam::Lifetime(ref mut param) => { syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(bound); param.bounds.push(bound.clone());
} }
syn::GenericParam::Type(ref mut param) => { syn::GenericParam::Type(ref mut param) => {
param.bounds.push(syn::TypeParamBound::Lifetime(bound)); param
.bounds
.push(syn::TypeParamBound::Lifetime(bound.clone()));
} }
syn::GenericParam::Const(_) => {} syn::GenericParam::Const(_) => {}
} }
@@ -257,23 +285,24 @@ fn type_of_item(cont: &Container) -> syn::Type {
path: syn::Path { path: syn::Path {
leading_colon: None, leading_colon: None,
segments: vec![syn::PathSegment { segments: vec![syn::PathSegment {
ident: cont.ident, ident: cont.ident.clone(),
arguments: syn::PathArguments::AngleBracketed( arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments { syn::AngleBracketedGenericArguments {
colon2_token: None, colon2_token: None,
lt_token: Default::default(), lt_token: Default::default(),
args: cont.generics args: cont
.generics
.params .params
.iter() .iter()
.map(|param| match *param { .map(|param| match *param {
syn::GenericParam::Type(ref param) => { syn::GenericParam::Type(ref param) => {
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
qself: None, qself: None,
path: param.ident.into(), path: param.ident.clone().into(),
})) }))
} }
syn::GenericParam::Lifetime(ref param) => { syn::GenericParam::Lifetime(ref param) => {
syn::GenericArgument::Lifetime(param.lifetime) syn::GenericArgument::Lifetime(param.lifetime.clone())
} }
syn::GenericParam::Const(_) => { syn::GenericParam::Const(_) => {
panic!("Serde does not support const generics yet"); panic!("Serde does not support const generics yet");
+238 -156
View File
@@ -6,8 +6,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use proc_macro2::{Literal, Span}; use proc_macro2::{Literal, Span, TokenStream};
use quote::{ToTokens, Tokens}; use quote::ToTokens;
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member}; use syn::{self, Ident, Index, Member};
@@ -15,18 +15,19 @@ use syn::{self, Ident, Index, Member};
use bound; use bound;
use fragment::{Expr, Fragment, Match, Stmts}; use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant}; use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{self, attr}; use internals::{attr, Ctxt, Derive};
use pretend; use pretend;
use try; use try;
use std::collections::BTreeSet; use std::collections::BTreeSet;
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, String> { pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
let ctxt = internals::Ctxt::new(); let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input); let cont = Container::from_ast(&ctxt, input, Derive::Deserialize);
precondition(&ctxt, &cont);
try!(ctxt.check()); try!(ctxt.check());
let ident = cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params); let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new( let dummy_const = Ident::new(
@@ -80,6 +81,32 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
Ok(generated) Ok(generated)
} }
fn precondition(cx: &Ctxt, cont: &Container) {
precondition_sized(cx, cont);
precondition_no_de_lifetime(cx, cont);
}
fn precondition_sized(cx: &Ctxt, cont: &Container) {
if let Data::Struct(_, ref fields) = cont.data {
if let Some(last) = fields.last() {
if let syn::Type::Slice(_) = *last.ty {
cx.error("cannot deserialize a dynamically sized struct");
}
}
}
}
fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) {
if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) {
for param in cont.generics.lifetimes() {
if param.lifetime.to_string() == "'de" {
cx.error("cannot deserialize when there is a lifetime parameter called 'de");
return;
}
}
}
}
struct Parameters { struct Parameters {
/// Name of the type the `derive` is on. /// Name of the type the `derive` is on.
local: syn::Ident, local: syn::Ident,
@@ -103,10 +130,10 @@ struct Parameters {
impl Parameters { impl Parameters {
fn new(cont: &Container) -> Self { fn new(cont: &Container) -> Self {
let local = cont.ident; let local = cont.ident.clone();
let this = match cont.attrs.remote() { let this = match cont.attrs.remote() {
Some(remote) => remote.clone(), Some(remote) => remote.clone(),
None => cont.ident.into(), None => cont.ident.clone().into(),
}; };
let borrowed = borrowed_lifetimes(cont); let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed); let generics = build_generics(cont, &borrowed);
@@ -123,8 +150,8 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Deserializer methods. /// various Deserializer methods.
fn type_name(&self) -> &str { fn type_name(&self) -> String {
self.this.segments.last().unwrap().value().ident.as_ref() self.this.segments.last().unwrap().value().ident.to_string()
} }
} }
@@ -136,6 +163,9 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound); let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound);
let generics =
bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::de_bound);
match cont.attrs.de_bound() { match cont.attrs.de_bound() {
Some(predicates) => bound::with_where_predicates(&generics, predicates), Some(predicates) => bound::with_where_predicates(&generics, predicates),
None => { None => {
@@ -164,13 +194,19 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
} }
} }
// Fields with a `skip_deserializing` or `deserialize_with` attribute are not // Fields with a `skip_deserializing` or `deserialize_with` attribute, or which
// deserialized by us so we do not generate a bound. Fields with a `bound` // belong to a variant with a `skip_deserializing` or `deserialize_with`
// attribute specify their own bound so we do not generate one. All other fields // attribute, are not deserialized by us so we do not generate a bound. Fields
// may need a `T: Deserialize` bound where T is the type of the field. // with a `bound` attribute specify their own bound so we do not generate one.
// All other fields may need a `T: Deserialize` bound where T is the type of the
// field.
fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_deserializing() && field.deserialize_with().is_none() && field.de_bound().is_none() !field.skip_deserializing() && field.deserialize_with().is_none() && field.de_bound().is_none()
&& variant.map_or(true, |variant| variant.deserialize_with().is_none()) && variant.map_or(true, |variant| {
!variant.skip_deserializing()
&& variant.deserialize_with().is_none()
&& variant.de_bound().is_none()
})
} }
// Fields with a `default` attribute (not `default=...`), and fields with a // Fields with a `default` attribute (not `default=...`), and fields with a
@@ -233,21 +269,17 @@ fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
} }
fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(type_from) = cont.attrs.type_from() { if cont.attrs.transparent() {
deserialize_transparent(cont, params)
} else if let Some(type_from) = cont.attrs.type_from() {
deserialize_from(type_from) deserialize_from(type_from)
} else if let attr::Identifier::No = cont.attrs.identifier() { } else if let attr::Identifier::No = cont.attrs.identifier() {
match cont.data { match cont.data {
Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No)
} }
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields");
}
deserialize_tuple(None, params, fields, &cont.attrs, None) deserialize_tuple(None, params, fields, &cont.attrs, None)
} }
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
@@ -268,8 +300,11 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
// deserialize_in_place for remote derives. // deserialize_in_place for remote derives.
assert!(!params.has_getter); assert!(!params.has_getter);
if cont.attrs.type_from().is_some() || cont.attrs.identifier().is_some() if cont.attrs.transparent()
|| cont.data || cont.attrs.type_from().is_some()
|| cont.attrs.identifier().is_some()
|| cont
.data
.all_fields() .all_fields()
.all(|f| f.attrs.deserialize_with().is_some()) .all(|f| f.attrs.deserialize_with().is_some())
{ {
@@ -313,6 +348,41 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<
None None
} }
fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let fields = match cont.data {
Data::Struct(_, ref fields) => fields,
Data::Enum(_) => unreachable!(),
};
let this = &params.this;
let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap();
let path = match transparent_field.attrs.deserialize_with() {
Some(path) => quote!(#path),
None => quote!(_serde::Deserialize::deserialize),
};
let assign = fields.iter().map(|field| {
let member = &field.member;
if field as *const Field == transparent_field as *const Field {
quote!(#member: __transparent)
} else {
let value = match *field.attrs.default() {
attr::Default::Default => quote!(_serde::export::Default::default()),
attr::Default::Path(ref path) => quote!(#path()),
attr::Default::None => quote!(_serde::export::PhantomData),
};
quote!(#member: #value)
}
});
quote_block! {
_serde::export::Result::map(
#path(__deserializer),
|__transparent| #this { #(#assign),* })
}
}
fn deserialize_from(type_from: &syn::Type) -> Fragment { fn deserialize_from(type_from: &syn::Type) -> Fragment {
quote_block! { quote_block! {
_serde::export::Result::map( _serde::export::Result::map(
@@ -351,11 +421,11 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
} }
fn deserialize_tuple( fn deserialize_tuple(
variant_ident: Option<syn::Ident>, variant_ident: Option<&syn::Ident>,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<Tokens>, deserializer: Option<TokenStream>,
) -> Fragment { ) -> Fragment {
let this = &params.this; let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
@@ -368,7 +438,7 @@ fn deserialize_tuple(
// and use an `Into` conversion to get the remote type. If there are no // and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly. // getters then construct the target type directly.
let construct = if params.has_getter { let construct = if params.has_getter {
let local = params.local; let local = &params.local;
quote!(#local) quote!(#local)
} else { } else {
quote!(#this) quote!(#this)
@@ -376,7 +446,7 @@ fn deserialize_tuple(
let is_enum = variant_ident.is_some(); let is_enum = variant_ident.is_some();
let type_path = match variant_ident { let type_path = match variant_ident {
Some(variant_ident) => quote!(#construct::#variant_ident), Some(ref variant_ident) => quote!(#construct::#variant_ident),
None => construct, None => construct,
}; };
let expecting = match variant_ident { let expecting = match variant_ident {
@@ -392,7 +462,9 @@ fn deserialize_tuple(
None None
}; };
let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, false, cattrs)); let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, false, cattrs, &expecting,
));
let visitor_expr = quote! { let visitor_expr = quote! {
__Visitor { __Visitor {
@@ -453,7 +525,7 @@ fn deserialize_tuple_in_place(
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<Tokens>, deserializer: Option<TokenStream>,
) -> Fragment { ) -> Fragment {
let this = &params.this; let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
@@ -476,7 +548,7 @@ fn deserialize_tuple_in_place(
None None
}; };
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs)); let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
let visitor_expr = quote! { let visitor_expr = quote! {
__Visitor { __Visitor {
@@ -537,23 +609,26 @@ fn deserialize_tuple_in_place(
} }
fn deserialize_seq( fn deserialize_seq(
type_path: &Tokens, type_path: &TokenStream,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
is_struct: bool, is_struct: bool,
cattrs: &attr::Container, cattrs: &attr::Container,
expecting: &str,
) -> Fragment { ) -> Fragment {
let vars = (0..fields.len()).map(field_i as fn(_) -> _); let vars = (0..fields.len()).map(field_i as fn(_) -> _);
// XXX: do we need an error for flattening here?
let deserialized_count = fields let deserialized_count = fields
.iter() .iter()
.filter(|field| !field.attrs.skip_deserializing()) .filter(|field| !field.attrs.skip_deserializing())
.count(); .count();
let expecting = format!("tuple of {} elements", deserialized_count); let expecting = if deserialized_count == 1 {
format!("{} with 1 element", expecting)
} else {
format!("{} with {} elements", expecting, deserialized_count)
};
let mut index_in_seq = 0usize; let mut index_in_seq = 0_usize;
let let_values = vars.clone().zip(fields).map(|(var, field)| { let let_values = vars.clone().zip(fields).map(|(var, field)| {
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(field, cattrs)); let default = Expr(expr_is_missing(field, cattrs));
@@ -593,7 +668,7 @@ fn deserialize_seq(
}); });
let mut result = if is_struct { let mut result = if is_struct {
let names = fields.iter().map(|f| &f.ident); let names = fields.iter().map(|f| &f.member);
quote! { quote! {
#type_path { #( #names: #vars ),* } #type_path { #( #names: #vars ),* }
} }
@@ -636,69 +711,60 @@ fn deserialize_seq_in_place(
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
expecting: &str,
) -> Fragment { ) -> Fragment {
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
// XXX: do we need an error for flattening here?
let deserialized_count = fields let deserialized_count = fields
.iter() .iter()
.filter(|field| !field.attrs.skip_deserializing()) .filter(|field| !field.attrs.skip_deserializing())
.count(); .count();
let expecting = format!("tuple of {} elements", deserialized_count); let expecting = if deserialized_count == 1 {
format!("{} with 1 element", expecting)
} else {
format!("{} with {} elements", expecting, deserialized_count)
};
let mut index_in_seq = 0usize; let mut index_in_seq = 0usize;
let write_values = vars.clone() let write_values = fields.iter().map(|field| {
.zip(fields) let member = &field.member;
.enumerate()
.map(|(field_index, (_, field))| {
// If there's no field name, assume we're a tuple-struct and use a numeric index
let field_name = field.ident.map(Member::Named).unwrap_or_else(|| {
Member::Unnamed(Index {
index: field_index as u32,
span: Span::call_site(),
})
});
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(field, cattrs)); let default = Expr(expr_is_missing(field, cattrs));
quote! { quote! {
self.place.#field_name = #default; self.place.#member = #default;
} }
} else { } else {
let return_invalid_length = quote! { let return_invalid_length = quote! {
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
}; };
let write = match field.attrs.deserialize_with() { let write = match field.attrs.deserialize_with() {
None => { None => {
quote! { quote! {
if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq, if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq,
_serde::private::de::InPlaceSeed(&mut self.place.#field_name))) _serde::private::de::InPlaceSeed(&mut self.place.#member)))
{ {
#return_invalid_length #return_invalid_length
}
} }
} }
Some(path) => { }
let (wrapper, wrapper_ty) = Some(path) => {
wrap_deserialize_field_with(params, field.ty, path); let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({ quote!({
#wrapper #wrapper
match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) { match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) {
_serde::export::Some(__wrap) => { _serde::export::Some(__wrap) => {
self.place.#field_name = __wrap.value; self.place.#member = __wrap.value;
} }
_serde::export::None => { _serde::export::None => {
#return_invalid_length #return_invalid_length
} }
} }
}) })
} }
}; };
index_in_seq += 1; index_in_seq += 1;
write write
} }
}); });
let this = &params.this; let this = &params.this;
let (_, ty_generics, _) = params.generics.split_for_impl(); let (_, ty_generics, _) = params.generics.split_for_impl();
@@ -723,7 +789,11 @@ fn deserialize_seq_in_place(
} }
} }
fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens { fn deserialize_newtype_struct(
type_path: &TokenStream,
params: &Parameters,
field: &Field,
) -> TokenStream {
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
let field_ty = field.ty; let field_ty = field.ty;
@@ -761,7 +831,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
} }
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> Tokens { fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> TokenStream {
// We do not generate deserialize_in_place if every field has a deserialize_with. // We do not generate deserialize_in_place if every field has a deserialize_with.
assert!(field.attrs.deserialize_with().is_none()); assert!(field.attrs.deserialize_with().is_none());
@@ -784,11 +854,11 @@ enum Untagged {
} }
fn deserialize_struct( fn deserialize_struct(
variant_ident: Option<syn::Ident>, variant_ident: Option<&syn::Ident>,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<Tokens>, deserializer: Option<TokenStream>,
untagged: &Untagged, untagged: &Untagged,
) -> Fragment { ) -> Fragment {
let is_enum = variant_ident.is_some(); let is_enum = variant_ident.is_some();
@@ -802,14 +872,14 @@ fn deserialize_struct(
// and use an `Into` conversion to get the remote type. If there are no // and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly. // getters then construct the target type directly.
let construct = if params.has_getter { let construct = if params.has_getter {
let local = params.local; let local = &params.local;
quote!(#local) quote!(#local)
} else { } else {
quote!(#this) quote!(#this)
}; };
let type_path = match variant_ident { let type_path = match variant_ident {
Some(variant_ident) => quote!(#construct::#variant_ident), Some(ref variant_ident) => quote!(#construct::#variant_ident),
None => construct, None => construct,
}; };
let expecting = match variant_ident { let expecting = match variant_ident {
@@ -817,7 +887,9 @@ fn deserialize_struct(
None => format!("struct {}", params.type_name()), None => format!("struct {}", params.type_name()),
}; };
let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, true, cattrs)); let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, true, cattrs, &expecting,
));
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() { let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs) deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs)
@@ -936,7 +1008,7 @@ fn deserialize_struct_in_place(
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<Tokens>, deserializer: Option<TokenStream>,
) -> Option<Fragment> { ) -> Option<Fragment> {
let is_enum = variant_ident.is_some(); let is_enum = variant_ident.is_some();
@@ -956,7 +1028,7 @@ fn deserialize_struct_in_place(
None => format!("struct {}", params.type_name()), None => format!("struct {}", params.type_name()),
}; };
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs)); let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
let (field_visitor, fields_stmt, visit_map) = let (field_visitor, fields_stmt, visit_map) =
deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs); deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs);
@@ -1216,7 +1288,7 @@ fn deserialize_internally_tagged_enum(
#variants_stmt #variants_stmt
let __tagged = try!(_serde::Deserializer::private_deserialize_internally_tagged_enum( let __tagged = try!(_serde::Deserializer::deserialize_any(
__deserializer, __deserializer,
_serde::private::de::TaggedContentVisitor::<__Field>::new(#tag))); _serde::private::de::TaggedContentVisitor::<__Field>::new(#tag)));
@@ -1321,7 +1393,7 @@ fn deserialize_adjacently_tagged_enum(
.filter(|&(_, variant)| !variant.attrs.skip_deserializing() && is_unit(variant)) .filter(|&(_, variant)| !variant.attrs.skip_deserializing() && is_unit(variant))
.map(|(i, variant)| { .map(|(i, variant)| {
let variant_index = field_i(i); let variant_index = field_i(i);
let variant_ident = variant.ident; let variant_ident = &variant.ident;
quote! { quote! {
__Field::#variant_index => _serde::export::Ok(#this::#variant_ident), __Field::#variant_index => _serde::export::Ok(#this::#variant_ident),
} }
@@ -1382,6 +1454,21 @@ fn deserialize_adjacently_tagged_enum(
} }
}; };
let finish_content_then_tag = if variant_arms.is_empty() {
quote! {
match try!(_serde::de::MapAccess::next_value::<__Field>(&mut __map)) {}
}
} else {
quote! {
let __ret = try!(match try!(_serde::de::MapAccess::next_value(&mut __map)) {
// Deserialize the buffered content now that we know the variant.
#(#variant_arms)*
});
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
};
quote_block! { quote_block! {
#variant_visitor #variant_visitor
@@ -1458,13 +1545,7 @@ fn deserialize_adjacently_tagged_enum(
// Second key is the tag. // Second key is the tag.
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
let __deserializer = _serde::private::de::ContentDeserializer::<__A::Error>::new(__content); let __deserializer = _serde::private::de::ContentDeserializer::<__A::Error>::new(__content);
// Parse the tag. #finish_content_then_tag
let __ret = try!(match try!(_serde::de::MapAccess::next_value(&mut __map)) {
// Deserialize the buffered content now that we know the variant.
#(#variant_arms)*
});
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
} }
// Second key is a duplicate of the content. // Second key is a duplicate of the content.
_serde::export::Some(_serde::private::de::TagOrContentField::Content) => { _serde::export::Some(_serde::private::de::TagOrContentField::Content) => {
@@ -1576,7 +1657,7 @@ fn deserialize_externally_tagged_variant(
}; };
} }
let variant_ident = variant.ident; let variant_ident = &variant.ident;
match variant.style { match variant.style {
Style::Unit => { Style::Unit => {
@@ -1607,19 +1688,19 @@ fn deserialize_internally_tagged_variant(
params: &Parameters, params: &Parameters,
variant: &Variant, variant: &Variant,
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Tokens, deserializer: TokenStream,
) -> Fragment { ) -> Fragment {
if variant.attrs.deserialize_with().is_some() { if variant.attrs.deserialize_with().is_some() {
return deserialize_untagged_variant(params, variant, cattrs, deserializer); return deserialize_untagged_variant(params, variant, cattrs, deserializer);
} }
let variant_ident = variant.ident; let variant_ident = &variant.ident;
match variant.style { match variant.style {
Style::Unit => { Style::Unit => {
let this = &params.this; let this = &params.this;
let type_name = params.type_name(); let type_name = params.type_name();
let variant_name = variant.ident.as_ref(); let variant_name = variant.ident.to_string();
quote_block! { quote_block! {
try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))); try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name)));
_serde::export::Ok(#this::#variant_ident) _serde::export::Ok(#this::#variant_ident)
@@ -1647,7 +1728,7 @@ fn deserialize_untagged_variant(
params: &Parameters, params: &Parameters,
variant: &Variant, variant: &Variant,
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Tokens, deserializer: TokenStream,
) -> Fragment { ) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() { if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
@@ -1658,13 +1739,13 @@ fn deserialize_untagged_variant(
}; };
} }
let variant_ident = variant.ident; let variant_ident = &variant.ident;
match variant.style { match variant.style {
Style::Unit => { Style::Unit => {
let this = &params.this; let this = &params.this;
let type_name = params.type_name(); let type_name = params.type_name();
let variant_name = variant.ident.as_ref(); let variant_name = variant.ident.to_string();
quote_expr! { quote_expr! {
match _serde::Deserializer::deserialize_any( match _serde::Deserializer::deserialize_any(
#deserializer, #deserializer,
@@ -1700,7 +1781,7 @@ fn deserialize_untagged_variant(
} }
fn deserialize_externally_tagged_newtype_variant( fn deserialize_externally_tagged_newtype_variant(
variant_ident: syn::Ident, variant_ident: &syn::Ident,
params: &Parameters, params: &Parameters,
field: &Field, field: &Field,
) -> Fragment { ) -> Fragment {
@@ -1727,10 +1808,10 @@ fn deserialize_externally_tagged_newtype_variant(
} }
fn deserialize_untagged_newtype_variant( fn deserialize_untagged_newtype_variant(
variant_ident: syn::Ident, variant_ident: &syn::Ident,
params: &Parameters, params: &Parameters,
field: &Field, field: &Field,
deserializer: &Tokens, deserializer: &TokenStream,
) -> Fragment { ) -> Fragment {
let this = &params.this; let this = &params.this;
let field_ty = field.ty; let field_ty = field.ty;
@@ -1744,10 +1825,8 @@ fn deserialize_untagged_newtype_variant(
} }
Some(path) => { Some(path) => {
quote_block! { quote_block! {
let __value: #field_ty = _serde::export::Result::map( let __value: _serde::export::Result<#field_ty, _> = #path(#deserializer);
#path(#deserializer), _serde::export::Result::map(__value, #this::#variant_ident)
#this::#variant_ident);
__value
} }
} }
} }
@@ -1829,7 +1908,7 @@ fn deserialize_custom_identifier(
let this = quote!(#this); let this = quote!(#this);
let (ordinary, fallthrough) = if let Some(last) = variants.last() { let (ordinary, fallthrough) = if let Some(last) = variants.last() {
let last_ident = last.ident; let last_ident = &last.ident;
if last.attrs.other() { if last.attrs.other() {
let ordinary = &variants[..variants.len() - 1]; let ordinary = &variants[..variants.len() - 1];
let fallthrough = quote!(_serde::export::Ok(#this::#last_ident)); let fallthrough = quote!(_serde::export::Ok(#this::#last_ident));
@@ -1852,7 +1931,12 @@ fn deserialize_custom_identifier(
let names_idents: Vec<_> = ordinary let names_idents: Vec<_> = ordinary
.iter() .iter()
.map(|variant| (variant.attrs.name().deserialize_name(), variant.ident)) .map(|variant| {
(
variant.attrs.name().deserialize_name(),
variant.ident.clone(),
)
})
.collect(); .collect();
let names = names_idents.iter().map(|&(ref name, _)| name); let names = names_idents.iter().map(|&(ref name, _)| name);
@@ -1905,10 +1989,10 @@ fn deserialize_custom_identifier(
} }
fn deserialize_identifier( fn deserialize_identifier(
this: &Tokens, this: &TokenStream,
fields: &[(String, Ident)], fields: &[(String, Ident)],
is_variant: bool, is_variant: bool,
fallthrough: Option<Tokens>, fallthrough: Option<TokenStream>,
collect_other_fields: bool, collect_other_fields: bool,
) -> Fragment { ) -> Fragment {
let field_strs = fields.iter().map(|&(ref name, _)| name); let field_strs = fields.iter().map(|&(ref name, _)| name);
@@ -1946,9 +2030,7 @@ fn deserialize_identifier(
value_as_borrowed_str_content, value_as_borrowed_str_content,
value_as_bytes_content, value_as_bytes_content,
value_as_borrowed_bytes_content, value_as_borrowed_bytes_content,
) = if !collect_other_fields { ) = if collect_other_fields {
(None, None, None, None)
} else {
( (
Some(quote! { Some(quote! {
let __value = _serde::private::de::Content::String(__value.to_string()); let __value = _serde::private::de::Content::String(__value.to_string());
@@ -1963,6 +2045,8 @@ fn deserialize_identifier(
let __value = _serde::private::de::Content::Bytes(__value); let __value = _serde::private::de::Content::Bytes(__value);
}), }),
) )
} else {
(None, None, None, None)
}; };
let fallthrough_arm = if let Some(fallthrough) = fallthrough { let fallthrough_arm = if let Some(fallthrough) = fallthrough {
@@ -1977,7 +2061,7 @@ fn deserialize_identifier(
} }
}; };
let variant_indices = 0u64..; let variant_indices = 0_u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_other = if collect_other_fields { let visit_other = if collect_other_fields {
quote! { quote! {
@@ -2162,7 +2246,7 @@ fn deserialize_identifier(
} }
fn deserialize_struct_as_struct_visitor( fn deserialize_struct_as_struct_visitor(
struct_path: &Tokens, struct_path: &TokenStream,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
@@ -2191,7 +2275,7 @@ fn deserialize_struct_as_struct_visitor(
} }
fn deserialize_struct_as_map_visitor( fn deserialize_struct_as_map_visitor(
struct_path: &Tokens, struct_path: &TokenStream,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
@@ -2211,7 +2295,7 @@ fn deserialize_struct_as_map_visitor(
} }
fn deserialize_map( fn deserialize_map(
struct_path: &Tokens, struct_path: &TokenStream,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
@@ -2366,12 +2450,12 @@ fn deserialize_map(
}; };
let result = fields_names.iter().map(|&(field, ref name)| { let result = fields_names.iter().map(|&(field, ref name)| {
let ident = field.ident.expect("struct contains unnamed fields"); let member = &field.member;
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let value = Expr(expr_is_missing(field, cattrs)); let value = Expr(expr_is_missing(field, cattrs));
quote!(#ident: #value) quote!(#member: #value)
} else { } else {
quote!(#ident: #name) quote!(#member: #name)
} }
}); });
@@ -2476,19 +2560,19 @@ fn deserialize_map_in_place(
.filter(|&&(field, _)| !field.attrs.skip_deserializing()) .filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|&(field, ref name)| { .map(|&(field, ref name)| {
let deser_name = field.attrs.name().deserialize_name(); let deser_name = field.attrs.name().deserialize_name();
let field_name = field.ident; let member = &field.member;
let visit = match field.attrs.deserialize_with() { let visit = match field.attrs.deserialize_with() {
None => { None => {
quote! { quote! {
try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#field_name))) try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#member)))
} }
} }
Some(path) => { Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({ quote!({
#wrapper #wrapper
self.place.#field_name = try!(_serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map)).value self.place.#member = try!(_serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map)).value
}) })
} }
}; };
@@ -2540,7 +2624,8 @@ fn deserialize_map_in_place(
let missing_expr = expr_is_missing(field, cattrs); let missing_expr = expr_is_missing(field, cattrs);
// If missing_expr unconditionally returns an error, don't try // If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place. // to assign its value to self.place.
if field.attrs.default().is_none() && cattrs.default().is_none() if field.attrs.default().is_none()
&& cattrs.default().is_none()
&& field.attrs.deserialize_with().is_some() && field.attrs.deserialize_with().is_some()
{ {
let missing_expr = Stmts(missing_expr); let missing_expr = Stmts(missing_expr);
@@ -2550,11 +2635,11 @@ fn deserialize_map_in_place(
} }
} }
} else { } else {
let field_name = field.ident; let member = &field.member;
let missing_expr = Expr(missing_expr); let missing_expr = Expr(missing_expr);
quote! { quote! {
if !#name { if !#name {
self.place.#field_name = #missing_expr; self.place.#member = #missing_expr;
}; };
} }
} }
@@ -2598,9 +2683,9 @@ fn field_i(i: usize) -> Ident {
/// in a trait to prevent it from accessing the internal `Deserialize` state. /// in a trait to prevent it from accessing the internal `Deserialize` state.
fn wrap_deserialize_with( fn wrap_deserialize_with(
params: &Parameters, params: &Parameters,
value_ty: &Tokens, value_ty: &TokenStream,
deserialize_with: &syn::ExprPath, deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens) { ) -> (TokenStream, TokenStream) {
let this = &params.this; let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params); split_with_de_lifetime(params);
@@ -2636,7 +2721,7 @@ fn wrap_deserialize_field_with(
params: &Parameters, params: &Parameters,
field_ty: &syn::Type, field_ty: &syn::Type,
deserialize_with: &syn::ExprPath, deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens) { ) -> (TokenStream, TokenStream) {
wrap_deserialize_with(params, &quote!(#field_ty), deserialize_with) wrap_deserialize_with(params, &quote!(#field_ty), deserialize_with)
} }
@@ -2644,9 +2729,9 @@ fn wrap_deserialize_variant_with(
params: &Parameters, params: &Parameters,
variant: &Variant, variant: &Variant,
deserialize_with: &syn::ExprPath, deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens, Tokens) { ) -> (TokenStream, TokenStream, TokenStream) {
let this = &params.this; let this = &params.this;
let variant_ident = variant.ident; let variant_ident = &variant.ident;
let field_tys = variant.fields.iter().map(|field| field.ty); let field_tys = variant.fields.iter().map(|field| field.ty);
let (wrapper, wrapper_ty) = let (wrapper, wrapper_ty) =
@@ -2660,18 +2745,15 @@ fn wrap_deserialize_variant_with(
}); });
let unwrap_fn = match variant.style { let unwrap_fn = match variant.style {
Style::Struct if variant.fields.len() == 1 => { Style::Struct if variant.fields.len() == 1 => {
let field_ident = variant.fields[0].ident.unwrap(); let member = &variant.fields[0].member;
quote! { quote! {
|__wrap| #this::#variant_ident { #field_ident: __wrap.value } |__wrap| #this::#variant_ident { #member: __wrap.value }
} }
} }
Style::Struct => { Style::Struct => {
let field_idents = variant let members = variant.fields.iter().map(|field| &field.member);
.fields
.iter()
.map(|field| field.ident.as_ref().unwrap());
quote! { quote! {
|__wrap| #this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* } |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* }
} }
} }
Style::Tuple => quote! { Style::Tuple => quote! {
@@ -2701,8 +2783,8 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
match *cattrs.default() { match *cattrs.default() {
attr::Default::Default | attr::Default::Path(_) => { attr::Default::Default | attr::Default::Path(_) => {
let ident = field.ident; let member = &field.member;
return quote_expr!(__default.#ident); return quote_expr!(__default.#member);
} }
attr::Default::None => { /* below */ } attr::Default::None => { /* below */ }
} }
@@ -2729,7 +2811,7 @@ struct DeImplGenerics<'a>(&'a Parameters);
struct InPlaceImplGenerics<'a>(&'a Parameters); struct InPlaceImplGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeImplGenerics<'a> { impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
@@ -2744,7 +2826,7 @@ impl<'a> ToTokens for DeImplGenerics<'a> {
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
impl<'a> ToTokens for InPlaceImplGenerics<'a> { impl<'a> ToTokens for InPlaceImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut TokenStream) {
let place_lifetime = place_lifetime(); let place_lifetime = place_lifetime();
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
@@ -2752,12 +2834,12 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
for param in &mut generics.params { for param in &mut generics.params {
match *param { match *param {
syn::GenericParam::Lifetime(ref mut param) => { syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(place_lifetime.lifetime); param.bounds.push(place_lifetime.lifetime.clone());
} }
syn::GenericParam::Type(ref mut param) => { syn::GenericParam::Type(ref mut param) => {
param param.bounds.push(syn::TypeParamBound::Lifetime(
.bounds place_lifetime.lifetime.clone(),
.push(syn::TypeParamBound::Lifetime(place_lifetime.lifetime)); ));
} }
syn::GenericParam::Const(_) => {} syn::GenericParam::Const(_) => {}
} }
@@ -2789,7 +2871,7 @@ struct DeTypeGenerics<'a>(&'a Parameters);
struct InPlaceTypeGenerics<'a>(&'a Parameters); struct InPlaceTypeGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeTypeGenerics<'a> { impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() { if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef { let def = syn::LifetimeDef {
@@ -2810,7 +2892,7 @@ impl<'a> ToTokens for DeTypeGenerics<'a> {
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
impl<'a> ToTokens for InPlaceTypeGenerics<'a> { impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
generics.params = Some(syn::GenericParam::Lifetime(place_lifetime())) generics.params = Some(syn::GenericParam::Lifetime(place_lifetime()))
.into_iter() .into_iter()
+9 -8
View File
@@ -6,15 +6,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use quote::{ToTokens, Tokens}; use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::token; use syn::token;
pub enum Fragment { pub enum Fragment {
/// Tokens that can be used as an expression. /// Tokens that can be used as an expression.
Expr(Tokens), Expr(TokenStream),
/// Tokens that can be used inside a block. The surrounding curly braces are /// Tokens that can be used inside a block. The surrounding curly braces are
/// not part of these tokens. /// not part of these tokens.
Block(Tokens), Block(TokenStream),
} }
macro_rules! quote_expr { macro_rules! quote_expr {
@@ -33,7 +34,7 @@ macro_rules! quote_block {
/// Block fragments in curly braces. /// Block fragments in curly braces.
pub struct Expr(pub Fragment); pub struct Expr(pub Fragment);
impl ToTokens for Expr { impl ToTokens for Expr {
fn to_tokens(&self, out: &mut Tokens) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out), Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => { Fragment::Block(ref block) => {
@@ -46,7 +47,7 @@ impl ToTokens for Expr {
/// Interpolate a fragment as the statements of a block. /// Interpolate a fragment as the statements of a block.
pub struct Stmts(pub Fragment); pub struct Stmts(pub Fragment);
impl ToTokens for Stmts { impl ToTokens for Stmts {
fn to_tokens(&self, out: &mut Tokens) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out), Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => block.to_tokens(out), Fragment::Block(ref block) => block.to_tokens(out),
@@ -58,7 +59,7 @@ impl ToTokens for Stmts {
/// involves putting a comma after expressions and curly braces around blocks. /// involves putting a comma after expressions and curly braces around blocks.
pub struct Match(pub Fragment); pub struct Match(pub Fragment);
impl ToTokens for Match { impl ToTokens for Match {
fn to_tokens(&self, out: &mut Tokens) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match self.0 {
Fragment::Expr(ref expr) => { Fragment::Expr(ref expr) => {
expr.to_tokens(out); expr.to_tokens(out);
@@ -71,8 +72,8 @@ impl ToTokens for Match {
} }
} }
impl AsRef<Tokens> for Fragment { impl AsRef<TokenStream> for Fragment {
fn as_ref(&self) -> &Tokens { fn as_ref(&self) -> &TokenStream {
match *self { match *self {
Fragment::Expr(ref expr) => expr, Fragment::Expr(ref expr) => expr,
Fragment::Block(ref block) => block, Fragment::Block(ref block) => block,
+11 -8
View File
@@ -8,7 +8,7 @@
use internals::attr; use internals::attr;
use internals::check; use internals::check;
use internals::Ctxt; use internals::{Ctxt, Derive};
use syn; use syn;
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
@@ -32,7 +32,7 @@ pub struct Variant<'a> {
} }
pub struct Field<'a> { pub struct Field<'a> {
pub ident: Option<syn::Ident>, pub member: syn::Member,
pub attrs: attr::Field, pub attrs: attr::Field,
pub ty: &'a syn::Type, pub ty: &'a syn::Type,
pub original: &'a syn::Field, pub original: &'a syn::Field,
@@ -47,7 +47,7 @@ pub enum Style {
} }
impl<'a> Container<'a> { impl<'a> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> { pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Container<'a> {
let mut attrs = attr::Container::from_ast(cx, item); let mut attrs = attr::Container::from_ast(cx, item);
let mut data = match item.data { let mut data = match item.data {
@@ -86,13 +86,13 @@ impl<'a> Container<'a> {
attrs.mark_has_flatten(); attrs.mark_has_flatten();
} }
let item = Container { let mut item = Container {
ident: item.ident, ident: item.ident.clone(),
attrs: attrs, attrs: attrs,
data: data, data: data,
generics: &item.generics, generics: &item.generics,
}; };
check::check(cx, &item); check::check(cx, &mut item, derive);
item item
} }
} }
@@ -124,7 +124,7 @@ fn enum_from_ast<'a>(
let (style, fields) = let (style, fields) =
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
Variant { Variant {
ident: variant.ident, ident: variant.ident.clone(),
attrs: attrs, attrs: attrs,
style: style, style: style,
fields: fields, fields: fields,
@@ -166,7 +166,10 @@ fn fields_from_ast<'a>(
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, field)| Field { .map(|(i, field)| Field {
ident: field.ident, member: match field.ident {
Some(ref ident) => syn::Member::Named(ident.clone()),
None => syn::Member::Unnamed(i.into()),
},
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ty: &field.ty, ty: &field.ty,
original: field, original: field,
+150 -59
View File
@@ -105,6 +105,7 @@ impl Name {
/// Represents container (e.g. struct) attribute information /// Represents container (e.g. struct) attribute information
pub struct Container { pub struct Container {
name: Name, name: Name,
transparent: bool,
deny_unknown_fields: bool, deny_unknown_fields: bool,
default: Default, default: Default,
rename_all: RenameRule, rename_all: RenameRule,
@@ -181,6 +182,7 @@ impl Container {
pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self {
let mut ser_name = Attr::none(cx, "rename"); let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut transparent = BoolAttr::none(cx, "transparent");
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
let mut default = Attr::none(cx, "default"); let mut default = Attr::none(cx, "default");
let mut rename_all = Attr::none(cx, "rename_all"); let mut rename_all = Attr::none(cx, "rename_all");
@@ -200,7 +202,7 @@ impl Container {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value()); ser_name.set(s.value());
de_name.set(s.value()); de_name.set(s.value());
} }
@@ -216,7 +218,7 @@ impl Container {
// Parse `#[serde(rename_all = "foo")]` // Parse `#[serde(rename_all = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename_all" => { Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) { match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!( Err(()) => cx.error(format!(
@@ -228,13 +230,18 @@ impl Container {
} }
} }
// Parse `#[serde(transparent)]`
Meta(Word(ref word)) if word == "transparent" => {
transparent.set_true();
}
// Parse `#[serde(deny_unknown_fields)]` // Parse `#[serde(deny_unknown_fields)]`
Meta(Word(word)) if word == "deny_unknown_fields" => { Meta(Word(ref word)) if word == "deny_unknown_fields" => {
deny_unknown_fields.set_true(); deny_unknown_fields.set_true();
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
Meta(Word(word)) if word == "default" => match item.data { Meta(Word(ref word)) if word == "default" => match item.data {
syn::Data::Struct(syn::DataStruct { syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_), fields: syn::Fields::Named(_),
.. ..
@@ -249,7 +256,7 @@ impl Container {
// Parse `#[serde(default = "...")]` // Parse `#[serde(default = "...")]`
Meta(NameValue(ref m)) if m.ident == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
match item.data { match item.data {
syn::Data::Struct(syn::DataStruct { syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_), fields: syn::Fields::Named(_),
@@ -268,7 +275,7 @@ impl Container {
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
Meta(NameValue(ref m)) if m.ident == "bound" => { Meta(NameValue(ref m)) if m.ident == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{ {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -284,7 +291,7 @@ impl Container {
} }
// Parse `#[serde(untagged)]` // Parse `#[serde(untagged)]`
Meta(Word(word)) if word == "untagged" => match item.data { Meta(Word(ref word)) if word == "untagged" => match item.data {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
untagged.set_true(); untagged.set_true();
} }
@@ -295,7 +302,7 @@ impl Container {
// Parse `#[serde(tag = "type")]` // Parse `#[serde(tag = "type")]`
Meta(NameValue(ref m)) if m.ident == "tag" => { Meta(NameValue(ref m)) if m.ident == "tag" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match item.data { match item.data {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
internal_tag.set(s.value()); internal_tag.set(s.value());
@@ -309,7 +316,7 @@ impl Container {
// Parse `#[serde(content = "c")]` // Parse `#[serde(content = "c")]`
Meta(NameValue(ref m)) if m.ident == "content" => { Meta(NameValue(ref m)) if m.ident == "content" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match item.data { match item.data {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
content.set(s.value()); content.set(s.value());
@@ -324,23 +331,23 @@ impl Container {
// Parse `#[serde(from = "Type")] // Parse `#[serde(from = "Type")]
Meta(NameValue(ref m)) if m.ident == "from" => { Meta(NameValue(ref m)) if m.ident == "from" => {
if let Ok(from_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
type_from.set_opt(Some(from_ty)); type_from.set_opt(Some(from_ty));
} }
} }
// Parse `#[serde(into = "Type")] // Parse `#[serde(into = "Type")]
Meta(NameValue(ref m)) if m.ident == "into" => { Meta(NameValue(ref m)) if m.ident == "into" => {
if let Ok(into_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
type_into.set_opt(Some(into_ty)); type_into.set_opt(Some(into_ty));
} }
} }
// Parse `#[serde(remote = "...")]` // Parse `#[serde(remote = "...")]`
Meta(NameValue(ref m)) if m.ident == "remote" => { Meta(NameValue(ref m)) if m.ident == "remote" => {
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) {
if is_primitive_path(&path, "Self") { if is_primitive_path(&path, "Self") {
remote.set(item.ident.into()); remote.set(item.ident.clone().into());
} else { } else {
remote.set(path); remote.set(path);
} }
@@ -348,12 +355,12 @@ impl Container {
} }
// Parse `#[serde(field_identifier)]` // Parse `#[serde(field_identifier)]`
Meta(Word(word)) if word == "field_identifier" => { Meta(Word(ref word)) if word == "field_identifier" => {
field_identifier.set_true(); field_identifier.set_true();
} }
// Parse `#[serde(variant_identifier)]` // Parse `#[serde(variant_identifier)]`
Meta(Word(word)) if word == "variant_identifier" => { Meta(Word(ref word)) if word == "variant_identifier" => {
variant_identifier.set_true(); variant_identifier.set_true();
} }
@@ -376,6 +383,7 @@ impl Container {
serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()), serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()),
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()), deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
}, },
transparent: transparent.get(),
deny_unknown_fields: deny_unknown_fields.get(), deny_unknown_fields: deny_unknown_fields.get(),
default: default.get().unwrap_or(Default::None), default: default.get().unwrap_or(Default::None),
rename_all: rename_all.get().unwrap_or(RenameRule::None), rename_all: rename_all.get().unwrap_or(RenameRule::None),
@@ -398,6 +406,10 @@ impl Container {
&self.rename_all &self.rename_all
} }
pub fn transparent(&self) -> bool {
self.transparent
}
pub fn deny_unknown_fields(&self) -> bool { pub fn deny_unknown_fields(&self) -> bool {
self.deny_unknown_fields self.deny_unknown_fields
} }
@@ -527,6 +539,8 @@ pub struct Variant {
ser_renamed: bool, ser_renamed: bool,
de_renamed: bool, de_renamed: bool,
rename_all: RenameRule, rename_all: RenameRule,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
skip_deserializing: bool, skip_deserializing: bool,
skip_serializing: bool, skip_serializing: bool,
other: bool, other: bool,
@@ -542,6 +556,8 @@ impl Variant {
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
let mut rename_all = Attr::none(cx, "rename_all"); let mut rename_all = Attr::none(cx, "rename_all");
let mut ser_bound = Attr::none(cx, "bound");
let mut de_bound = Attr::none(cx, "bound");
let mut other = BoolAttr::none(cx, "other"); let mut other = BoolAttr::none(cx, "other");
let mut serialize_with = Attr::none(cx, "serialize_with"); let mut serialize_with = Attr::none(cx, "serialize_with");
let mut deserialize_with = Attr::none(cx, "deserialize_with"); let mut deserialize_with = Attr::none(cx, "deserialize_with");
@@ -552,7 +568,7 @@ impl Variant {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value()); ser_name.set(s.value());
de_name.set(s.value()); de_name.set(s.value());
} }
@@ -568,7 +584,7 @@ impl Variant {
// Parse `#[serde(rename_all = "foo")]` // Parse `#[serde(rename_all = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename_all" => { Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) { match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!( Err(()) => cx.error(format!(
@@ -580,24 +596,48 @@ impl Variant {
} }
} }
// Parse `#[serde(skip)]`
Meta(Word(ref word)) if word == "skip" => {
skip_serializing.set_true();
skip_deserializing.set_true();
}
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
Meta(Word(word)) if word == "skip_deserializing" => { Meta(Word(ref word)) if word == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing)]` // Parse `#[serde(skip_serializing)]`
Meta(Word(word)) if word == "skip_serializing" => { Meta(Word(ref word)) if word == "skip_serializing" => {
skip_serializing.set_true(); skip_serializing.set_true();
} }
// Parse `#[serde(other)]` // Parse `#[serde(other)]`
Meta(Word(word)) if word == "other" => { Meta(Word(ref word)) if word == "other" => {
other.set_true(); other.set_true();
} }
// Parse `#[serde(bound = "D: Serialize")]`
Meta(NameValue(ref m)) if m.ident == "bound" => {
if let Ok(where_predicates) =
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
}
}
// Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]`
Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
}
}
// Parse `#[serde(with = "...")]` // Parse `#[serde(with = "...")]`
Meta(NameValue(ref m)) if m.ident == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path ser_path
.path .path
@@ -615,14 +655,14 @@ impl Variant {
// Parse `#[serde(serialize_with = "...")]` // Parse `#[serde(serialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "serialize_with" => { Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
serialize_with.set(path); serialize_with.set(path);
} }
} }
// Parse `#[serde(deserialize_with = "...")]` // Parse `#[serde(deserialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
deserialize_with.set(path); deserialize_with.set(path);
} }
} }
@@ -663,6 +703,8 @@ impl Variant {
ser_renamed: ser_renamed, ser_renamed: ser_renamed,
de_renamed: de_renamed, de_renamed: de_renamed,
rename_all: rename_all.get().unwrap_or(RenameRule::None), rename_all: rename_all.get().unwrap_or(RenameRule::None),
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
skip_deserializing: skip_deserializing.get(), skip_deserializing: skip_deserializing.get(),
skip_serializing: skip_serializing.get(), skip_serializing: skip_serializing.get(),
other: other.get(), other: other.get(),
@@ -689,6 +731,14 @@ impl Variant {
&self.rename_all &self.rename_all
} }
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
self.ser_bound.as_ref().map(|vec| &vec[..])
}
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
self.de_bound.as_ref().map(|vec| &vec[..])
}
pub fn skip_deserializing(&self) -> bool { pub fn skip_deserializing(&self) -> bool {
self.skip_deserializing self.skip_deserializing
} }
@@ -726,6 +776,7 @@ pub struct Field {
borrowed_lifetimes: BTreeSet<syn::Lifetime>, borrowed_lifetimes: BTreeSet<syn::Lifetime>,
getter: Option<syn::ExprPath>, getter: Option<syn::ExprPath>,
flatten: bool, flatten: bool,
transparent: bool,
} }
/// Represents the default to use for a field when deserializing. /// Represents the default to use for a field when deserializing.
@@ -739,7 +790,6 @@ pub enum Default {
} }
impl Default { impl Default {
#[cfg(feature = "deserialize_in_place")]
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
match *self { match *self {
Default::None => true, Default::None => true,
@@ -777,9 +827,7 @@ impl Field {
}; };
let variant_borrow = attrs let variant_borrow = attrs
.map(|variant| &variant.borrow) .and_then(|variant| variant.borrow.as_ref())
.unwrap_or(&None)
.as_ref()
.map(|borrow| vec![Meta(borrow.clone())]); .map(|borrow| vec![Meta(borrow.clone())]);
for meta_items in field for meta_items in field
@@ -792,7 +840,7 @@ impl Field {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value()); ser_name.set(s.value());
de_name.set(s.value()); de_name.set(s.value());
} }
@@ -807,57 +855,57 @@ impl Field {
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
Meta(Word(word)) if word == "default" => { Meta(Word(ref word)) if word == "default" => {
default.set(Default::Default); default.set(Default::Default);
} }
// Parse `#[serde(default = "...")]` // Parse `#[serde(default = "...")]`
Meta(NameValue(ref m)) if m.ident == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
default.set(Default::Path(path)); default.set(Default::Path(path));
} }
} }
// Parse `#[serde(skip_serializing)]` // Parse `#[serde(skip_serializing)]`
Meta(Word(word)) if word == "skip_serializing" => { Meta(Word(ref word)) if word == "skip_serializing" => {
skip_serializing.set_true(); skip_serializing.set_true();
} }
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
Meta(Word(word)) if word == "skip_deserializing" => { Meta(Word(ref word)) if word == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip)]` // Parse `#[serde(skip)]`
Meta(Word(word)) if word == "skip" => { Meta(Word(ref word)) if word == "skip" => {
skip_serializing.set_true(); skip_serializing.set_true();
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing_if = "...")]` // Parse `#[serde(skip_serializing_if = "...")]`
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => { Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
skip_serializing_if.set(path); skip_serializing_if.set(path);
} }
} }
// Parse `#[serde(serialize_with = "...")]` // Parse `#[serde(serialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "serialize_with" => { Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
serialize_with.set(path); serialize_with.set(path);
} }
} }
// Parse `#[serde(deserialize_with = "...")]` // Parse `#[serde(deserialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
deserialize_with.set(path); deserialize_with.set(path);
} }
} }
// Parse `#[serde(with = "...")]` // Parse `#[serde(with = "...")]`
Meta(NameValue(ref m)) if m.ident == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path ser_path
.path .path
@@ -876,7 +924,7 @@ impl Field {
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
Meta(NameValue(ref m)) if m.ident == "bound" => { Meta(NameValue(ref m)) if m.ident == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{ {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -892,7 +940,7 @@ impl Field {
} }
// Parse `#[serde(borrow)]` // Parse `#[serde(borrow)]`
Meta(Word(word)) if word == "borrow" => { Meta(Word(ref word)) if word == "borrow" => {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
borrowed_lifetimes.set(borrowable); borrowed_lifetimes.set(borrowable);
} }
@@ -900,9 +948,7 @@ impl Field {
// Parse `#[serde(borrow = "'a + 'b")]` // Parse `#[serde(borrow = "'a + 'b")]`
Meta(NameValue(ref m)) if m.ident == "borrow" => { Meta(NameValue(ref m)) if m.ident == "borrow" => {
if let Ok(lifetimes) = if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) {
parse_lit_into_lifetimes(cx, m.ident.as_ref(), &m.lit)
{
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
for lifetime in &lifetimes { for lifetime in &lifetimes {
if !borrowable.contains(lifetime) { if !borrowable.contains(lifetime) {
@@ -919,13 +965,13 @@ impl Field {
// Parse `#[serde(getter = "...")]` // Parse `#[serde(getter = "...")]`
Meta(NameValue(ref m)) if m.ident == "getter" => { Meta(NameValue(ref m)) if m.ident == "getter" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
getter.set(path); getter.set(path);
} }
} }
// Parse `#[serde(flatten)]` // Parse `#[serde(flatten)]`
Meta(Word(word)) if word == "flatten" => { Meta(Word(ref word)) if word == "flatten" => {
flatten.set_true(); flatten.set_true();
} }
@@ -1002,7 +1048,7 @@ impl Field {
}; };
deserialize_with.set_if_none(expr); deserialize_with.set_if_none(expr);
} }
} else if is_rptr(&field.ty, is_str) || is_rptr(&field.ty, is_slice_u8) { } else if is_implicitly_borrowed(&field.ty) {
// Types &str and &[u8] are always implicitly borrowed. No need for // Types &str and &[u8] are always implicitly borrowed. No need for
// a #[serde(borrow)]. // a #[serde(borrow)].
collect_lifetimes(&field.ty, &mut borrowed_lifetimes); collect_lifetimes(&field.ty, &mut borrowed_lifetimes);
@@ -1030,6 +1076,7 @@ impl Field {
borrowed_lifetimes: borrowed_lifetimes, borrowed_lifetimes: borrowed_lifetimes,
getter: getter.get(), getter: getter.get(),
flatten: flatten.get(), flatten: flatten.get(),
transparent: false,
} }
} }
@@ -1089,6 +1136,14 @@ impl Field {
pub fn flatten(&self) -> bool { pub fn flatten(&self) -> bool {
self.flatten self.flatten
} }
pub fn transparent(&self) -> bool {
self.transparent
}
pub fn mark_transparent(&mut self) {
self.transparent = true;
}
} }
type SerAndDe<T> = (Option<T>, Option<T>); type SerAndDe<T> = (Option<T>, Option<T>);
@@ -1101,21 +1156,22 @@ fn get_ser_and_de<'a, T, F>(
) -> Result<SerAndDe<T>, ()> ) -> Result<SerAndDe<T>, ()>
where where
T: 'a, T: 'a,
F: Fn(&Ctxt, &str, &str, &'a syn::Lit) -> Result<T, ()>, F: Fn(&Ctxt, &Ident, &Ident, &'a syn::Lit) -> Result<T, ()>,
{ {
let mut ser_meta = Attr::none(cx, attr_name); let mut ser_meta = Attr::none(cx, attr_name);
let mut de_meta = Attr::none(cx, attr_name); let mut de_meta = Attr::none(cx, attr_name);
let attr_name = Ident::new(attr_name, Span::call_site());
for meta in metas { for meta in metas {
match *meta { match *meta {
Meta(NameValue(ref meta)) if meta.ident == "serialize" => { Meta(NameValue(ref meta)) if meta.ident == "serialize" => {
if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
ser_meta.set(v); ser_meta.set(v);
} }
} }
Meta(NameValue(ref meta)) if meta.ident == "deserialize" => { Meta(NameValue(ref meta)) if meta.ident == "deserialize" => {
if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
de_meta.set(v); de_meta.set(v);
} }
} }
@@ -1164,8 +1220,8 @@ pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta
fn get_lit_str<'a>( fn get_lit_str<'a>(
cx: &Ctxt, cx: &Ctxt,
attr_name: &str, attr_name: &Ident,
meta_item_name: &str, meta_item_name: &Ident,
lit: &'a syn::Lit, lit: &'a syn::Lit,
) -> Result<&'a syn::LitStr, ()> { ) -> Result<&'a syn::LitStr, ()> {
if let syn::Lit::Str(ref lit) = *lit { if let syn::Lit::Str(ref lit) = *lit {
@@ -1179,7 +1235,7 @@ fn get_lit_str<'a>(
} }
} }
fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> { fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string) parse_lit_str(string)
.map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) .map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
@@ -1187,7 +1243,7 @@ fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn
fn parse_lit_into_expr_path( fn parse_lit_into_expr_path(
cx: &Ctxt, cx: &Ctxt,
attr_name: &str, attr_name: &Ident,
lit: &syn::Lit, lit: &syn::Lit,
) -> Result<syn::ExprPath, ()> { ) -> Result<syn::ExprPath, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
@@ -1197,8 +1253,8 @@ fn parse_lit_into_expr_path(
fn parse_lit_into_where( fn parse_lit_into_where(
cx: &Ctxt, cx: &Ctxt,
attr_name: &str, attr_name: &Ident,
meta_item_name: &str, meta_item_name: &Ident,
lit: &syn::Lit, lit: &syn::Lit,
) -> Result<Vec<syn::WherePredicate>, ()> { ) -> Result<Vec<syn::WherePredicate>, ()> {
let string = try!(get_lit_str(cx, attr_name, meta_item_name, lit)); let string = try!(get_lit_str(cx, attr_name, meta_item_name, lit));
@@ -1213,7 +1269,7 @@ fn parse_lit_into_where(
.map_err(|err| cx.error(err)) .map_err(|err| cx.error(err))
} }
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Type, ()> { fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Type, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string).map_err(|_| { parse_lit_str(string).map_err(|_| {
@@ -1229,7 +1285,7 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::
// lifetimes separated by `+`. // lifetimes separated by `+`.
fn parse_lit_into_lifetimes( fn parse_lit_into_lifetimes(
cx: &Ctxt, cx: &Ctxt,
attr_name: &str, attr_name: &Ident,
lit: &syn::Lit, lit: &syn::Lit,
) -> Result<BTreeSet<syn::Lifetime>, ()> { ) -> Result<BTreeSet<syn::Lifetime>, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
@@ -1250,7 +1306,7 @@ fn parse_lit_into_lifetimes(
if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) {
let mut set = BTreeSet::new(); let mut set = BTreeSet::new();
for lifetime in lifetimes { for lifetime in lifetimes {
if !set.insert(lifetime) { if !set.insert(lifetime.clone()) {
cx.error(format!("duplicate borrowed lifetime `{}`", lifetime)); cx.error(format!("duplicate borrowed lifetime `{}`", lifetime));
} }
} }
@@ -1264,6 +1320,14 @@ fn parse_lit_into_lifetimes(
Err(()) Err(())
} }
fn is_implicitly_borrowed(ty: &syn::Type) -> bool {
is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference)
}
fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool {
is_reference(ty, is_str) || is_reference(ty, is_slice_u8)
}
// Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". // Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T".
// This can have false negatives and false positives. // This can have false negatives and false positives.
// //
@@ -1311,6 +1375,31 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
} }
} }
fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
let path = match *ty {
syn::Type::Path(ref ty) => &ty.path,
_ => {
return false;
}
};
let seg = match path.segments.last() {
Some(seg) => seg.into_value(),
None => {
return false;
}
};
let args = match seg.arguments {
syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args,
_ => {
return false;
}
};
seg.ident == "Option" && args.len() == 1 && match args[0] {
syn::GenericArgument::Type(ref arg) => elem(arg),
_ => false,
}
}
// Whether the type looks like it might be `&T` where elem="T". This can have // Whether the type looks like it might be `&T` where elem="T". This can have
// false negatives and false positives. // false negatives and false positives.
// //
@@ -1331,7 +1420,7 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
// struct S<'a> { // struct S<'a> {
// r: &'a str, // r: &'a str,
// } // }
fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
match *ty { match *ty {
syn::Type::Reference(ref ty) => ty.mutability.is_none() && elem(&ty.elem), syn::Type::Reference(ref ty) => ty.mutability.is_none() && elem(&ty.elem),
_ => false, _ => false,
@@ -1357,7 +1446,9 @@ fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
} }
fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == primitive path.leading_colon.is_none()
&& path.segments.len() == 1
&& path.segments[0].ident == primitive
&& path.segments[0].arguments.is_empty() && path.segments[0].arguments.is_empty()
} }
+86 -15
View File
@@ -8,17 +8,19 @@
use internals::ast::{Container, Data, Field, Style}; use internals::ast::{Container, Data, Field, Style};
use internals::attr::{EnumTag, Identifier}; use internals::attr::{EnumTag, Identifier};
use internals::Ctxt; use internals::{Ctxt, Derive};
use syn::{Member, Type};
/// Cross-cutting checks that require looking at more than a single attrs /// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs. /// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) { pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_getter(cx, cont); check_getter(cx, cont);
check_flatten(cx, cont); check_flatten(cx, cont);
check_identifier(cx, cont); check_identifier(cx, cont);
check_variant_skip_attrs(cx, cont); check_variant_skip_attrs(cx, cont);
check_internal_tag_field_name_conflict(cx, cont); check_internal_tag_field_name_conflict(cx, cont);
check_adjacent_tag_conflict(cx, cont); check_adjacent_tag_conflict(cx, cont);
check_transparent(cx, cont, derive);
} }
/// Getters are only allowed inside structs (not enums) with the `remote` /// Getters are only allowed inside structs (not enums) with the `remote`
@@ -171,17 +173,14 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
)); ));
} }
for (i, field) in variant.fields.iter().enumerate() { for field in &variant.fields {
let ident = field let member = member_message(&field.member);
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
if field.attrs.skip_serializing() { if field.attrs.skip_serializing() {
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]", a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident variant.ident, member
)); ));
} }
@@ -189,7 +188,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]", a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident variant.ident, member
)); ));
} }
} }
@@ -204,17 +203,14 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
)); ));
} }
for (i, field) in variant.fields.iter().enumerate() { for field in &variant.fields {
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let ident = field let member = member_message(&field.member);
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \ "variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]", and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident variant.ident, member
)); ));
} }
} }
@@ -282,3 +278,78 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
cx.error(message); cx.error(message);
} }
} }
/// Enums and unit structs cannot be transparent.
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
if !cont.attrs.transparent() {
return;
}
if cont.attrs.type_from().is_some() {
cx.error("#[serde(transparent)] is not allowed with #[serde(from = \"...\")]");
}
if cont.attrs.type_into().is_some() {
cx.error("#[serde(transparent)] is not allowed with #[serde(into = \"...\")]");
}
let fields = match cont.data {
Data::Enum(_) => {
cx.error("#[serde(transparent)] is not allowed on an enum");
return;
}
Data::Struct(Style::Unit, _) => {
cx.error("#[serde(transparent)] is not allowed on a unit struct");
return;
}
Data::Struct(_, ref mut fields) => fields,
};
let mut transparent_field = None;
for field in fields {
if allow_transparent(field, derive) {
if transparent_field.is_some() {
cx.error(
"#[serde(transparent)] requires struct to have at most one transparent field",
);
return;
}
transparent_field = Some(field);
}
}
match transparent_field {
Some(transparent_field) => transparent_field.attrs.mark_transparent(),
None => match derive {
Derive::Serialize => {
cx.error("#[serde(transparent)] requires at least one field that is not skipped");
}
Derive::Deserialize => {
cx.error("#[serde(transparent)] requires at least one field that is neither skipped nor has a default");
}
},
}
}
fn member_message(member: &Member) -> String {
match *member {
Member::Named(ref ident) => format!("`{}`", ident),
Member::Unnamed(ref i) => i.index.to_string(),
}
}
fn allow_transparent(field: &Field, derive: Derive) -> bool {
if let Type::Path(ref ty) = *field.ty {
if let Some(seg) = ty.path.segments.last() {
if seg.into_value().ident == "PhantomData" {
return false;
}
}
}
match derive {
Derive::Serialize => !field.attrs.skip_serializing(),
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
}
}
+6
View File
@@ -14,3 +14,9 @@ pub use self::ctxt::Ctxt;
mod case; mod case;
mod check; mod check;
#[derive(Copy, Clone)]
pub enum Derive {
Serialize,
Deserialize,
}
+15 -2
View File
@@ -22,10 +22,23 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.48")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.61")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr( #![cfg_attr(
feature = "cargo-clippy", feature = "cargo-clippy",
allow(enum_variant_names, redundant_field_names, too_many_arguments, used_underscore_binding) allow(
enum_variant_names, redundant_field_names, too_many_arguments, used_underscore_binding,
cyclomatic_complexity
)
)]
// Whitelisted clippy_pedantic lints
#![cfg_attr(
feature = "cargo-clippy",
allow(
items_after_statements, doc_markdown, stutter, similar_names, use_self, single_match_else,
enum_glob_use, match_same_arms, filter_map, cast_possible_truncation
)
)] )]
// The `quote!` macro requires deep recursion. // The `quote!` macro requires deep recursion.
#![recursion_limit = "512"] #![recursion_limit = "512"]
+13 -14
View File
@@ -1,5 +1,4 @@
use proc_macro2::Span; use proc_macro2::{Span, TokenStream};
use quote::Tokens;
use syn::Ident; use syn::Ident;
use internals::ast::{Container, Data, Field, Style}; use internals::ast::{Container, Data, Field, Style};
@@ -21,7 +20,7 @@ use internals::ast::{Container, Data, Field, Style};
// 8 | enum EnumDef { V } // 8 | enum EnumDef { V }
// | ^ // | ^
// //
pub fn pretend_used(cont: &Container) -> Tokens { pub fn pretend_used(cont: &Container) -> TokenStream {
let pretend_fields = pretend_fields_used(cont); let pretend_fields = pretend_fields_used(cont);
let pretend_variants = pretend_variants_used(cont); let pretend_variants = pretend_variants_used(cont);
@@ -49,8 +48,8 @@ pub fn pretend_used(cont: &Container) -> Tokens {
// The `ref` is important in case the user has written a Drop impl on their // The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop // type. Rust does not allow destructuring a struct or enum that has a Drop
// impl. // impl.
fn pretend_fields_used(cont: &Container) -> Tokens { fn pretend_fields_used(cont: &Container) -> TokenStream {
let type_ident = cont.ident; let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl(); let (_, ty_generics, _) = cont.generics.split_for_impl();
let patterns = match cont.data { let patterns = match cont.data {
@@ -58,7 +57,7 @@ fn pretend_fields_used(cont: &Container) -> Tokens {
.iter() .iter()
.filter_map(|variant| match variant.style { .filter_map(|variant| match variant.style {
Style::Struct => { Style::Struct => {
let variant_ident = variant.ident; let variant_ident = &variant.ident;
let pat = struct_pattern(&variant.fields); let pat = struct_pattern(&variant.fields);
Some(quote!(#type_ident::#variant_ident #pat)) Some(quote!(#type_ident::#variant_ident #pat))
} }
@@ -93,7 +92,7 @@ fn pretend_fields_used(cont: &Container) -> Tokens {
// _ => {} // _ => {}
// } // }
// //
fn pretend_variants_used(cont: &Container) -> Tokens { fn pretend_variants_used(cont: &Container) -> TokenStream {
let variants = match cont.data { let variants = match cont.data {
Data::Enum(ref variants) => variants, Data::Enum(ref variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => {
@@ -101,20 +100,20 @@ fn pretend_variants_used(cont: &Container) -> Tokens {
} }
}; };
let type_ident = cont.ident; let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl(); let (_, ty_generics, _) = cont.generics.split_for_impl();
let turbofish = ty_generics.as_turbofish(); let turbofish = ty_generics.as_turbofish();
let cases = variants.iter().map(|variant| { let cases = variants.iter().map(|variant| {
let variant_ident = variant.ident; let variant_ident = &variant.ident;
let placeholders = &(0..variant.fields.len()) let placeholders = &(0..variant.fields.len())
.map(|i| Ident::new(&format!("__v{}", i), Span::call_site())) .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let pat = match variant.style { let pat = match variant.style {
Style::Struct => { Style::Struct => {
let names = variant.fields.iter().map(|field| field.ident); let members = variant.fields.iter().map(|field| &field.member);
quote!({ #(#names: #placeholders),* }) quote!({ #(#members: #placeholders),* })
} }
Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
Style::Unit => quote!(), Style::Unit => quote!(),
@@ -133,9 +132,9 @@ fn pretend_variants_used(cont: &Container) -> Tokens {
quote!(#(#cases)*) quote!(#(#cases)*)
} }
fn struct_pattern(fields: &[Field]) -> Tokens { fn struct_pattern(fields: &[Field]) -> TokenStream {
let names = fields.iter().map(|field| field.ident); let members = fields.iter().map(|field| &field.member);
let placeholders = let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#names: ref #placeholders),* }) quote!({ #(#members: ref #placeholders),* })
} }
+125 -76
View File
@@ -6,27 +6,24 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use proc_macro2::Span; use proc_macro2::{Span, TokenStream};
use quote::Tokens;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member}; use syn::{self, Ident, Index, Member};
use bound; use bound;
use fragment::{Fragment, Match, Stmts}; use fragment::{Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant}; use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, Ctxt}; use internals::{attr, Ctxt, Derive};
use pretend; use pretend;
use try; use try;
use std::u32; pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, String> {
let ctxt = Ctxt::new(); let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input); let cont = Container::from_ast(&ctxt, input, Derive::Serialize);
precondition(&ctxt, &cont); precondition(&ctxt, &cont);
try!(ctxt.check()); try!(ctxt.check());
let ident = cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::call_site()); let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::call_site());
@@ -112,7 +109,7 @@ impl Parameters {
let this = match cont.attrs.remote() { let this = match cont.attrs.remote() {
Some(remote) => remote.clone(), Some(remote) => remote.clone(),
None => cont.ident.into(), None => cont.ident.clone().into(),
}; };
let generics = build_generics(cont); let generics = build_generics(cont);
@@ -127,8 +124,8 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Serializer methods. /// various Serializer methods.
fn type_name(&self) -> &str { fn type_name(&self) -> String {
self.this.segments.last().unwrap().value().ident.as_ref() self.this.segments.last().unwrap().value().ident.to_string()
} }
} }
@@ -140,6 +137,9 @@ fn build_generics(cont: &Container) -> syn::Generics {
let generics = let generics =
bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound); bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound);
let generics =
bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound);
match cont.attrs.ser_bound() { match cont.attrs.ser_bound() {
Some(predicates) => bound::with_where_predicates(&generics, predicates), Some(predicates) => bound::with_where_predicates(&generics, predicates),
None => bound::with_bound( None => bound::with_bound(
@@ -152,31 +152,31 @@ fn build_generics(cont: &Container) -> syn::Generics {
} }
// Fields with a `skip_serializing` or `serialize_with` attribute, or which // Fields with a `skip_serializing` or `serialize_with` attribute, or which
// belong to a variant with a `serialize_with` attribute, are not serialized by // belong to a variant with a 'skip_serializing` or `serialize_with` attribute,
// us so we do not generate a bound. Fields with a `bound` attribute specify // are not serialized by us so we do not generate a bound. Fields with a `bound`
// their own bound so we do not generate one. All other fields may need a `T: // attribute specify their own bound so we do not generate one. All other fields
// Serialize` bound where T is the type of the field. // may need a `T: Serialize` bound where T is the type of the field.
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_serializing() && field.serialize_with().is_none() && field.ser_bound().is_none() !field.skip_serializing() && field.serialize_with().is_none() && field.ser_bound().is_none()
&& variant.map_or(true, |variant| variant.serialize_with().is_none()) && variant.map_or(true, |variant| {
!variant.skip_serializing()
&& variant.serialize_with().is_none()
&& variant.ser_bound().is_none()
})
} }
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(type_into) = cont.attrs.type_into() { if cont.attrs.transparent() {
serialize_transparent(cont, params)
} else if let Some(type_into) = cont.attrs.type_into() {
serialize_into(params, type_into) serialize_into(params, type_into)
} else { } else {
match cont.data { match cont.data {
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
serialize_struct(params, fields, &cont.attrs) serialize_struct(params, fields, &cont.attrs)
} }
Data::Struct(Style::Tuple, ref fields) => { Data::Struct(Style::Tuple, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields");
}
serialize_tuple_struct(params, fields, &cont.attrs) serialize_tuple_struct(params, fields, &cont.attrs)
} }
Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Newtype, ref fields) => {
@@ -187,8 +187,28 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
} }
} }
fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let fields = match cont.data {
Data::Struct(_, ref fields) => fields,
Data::Enum(_) => unreachable!(),
};
let self_var = &params.self_var;
let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap();
let member = &transparent_field.member;
let path = match transparent_field.attrs.serialize_with() {
Some(path) => quote!(#path),
None => quote!(_serde::Serialize::serialize),
};
quote_block! {
#path(&#self_var.#member, __serializer)
}
}
fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
let self_var = params.self_var; let self_var = &params.self_var;
quote_block! { quote_block! {
_serde::Serialize::serialize( _serde::Serialize::serialize(
&_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)), &_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)),
@@ -239,8 +259,28 @@ fn serialize_tuple_struct(
serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct);
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0); let mut serialized_fields = fields
.iter()
.enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(|(i, field)| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let index = syn::Index {
index: i as u32,
span: Span::call_site(),
};
let field_expr = get_member(params, field, &Member::Unnamed(index));
quote!(if #path(#field_expr) { 0 } else { 1 })
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! { quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)); let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len));
@@ -250,7 +290,7 @@ fn serialize_tuple_struct(
} }
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
assert!(fields.len() as u64 <= u64::from(u32::MAX)); assert!(fields.len() as u64 <= u64::from(u32::max_value()));
if cattrs.has_flatten() { if cattrs.has_flatten() {
serialize_struct_as_map(params, fields, cattrs) serialize_struct_as_map(params, fields, cattrs)
@@ -280,8 +320,7 @@ fn serialize_struct_as_struct(
.map(|field| match field.attrs.skip_serializing_if() { .map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1), None => quote!(1),
Some(path) => { Some(path) => {
let ident = field.ident.expect("struct has unnamed fields"); let field_expr = get_member(params, field, &field.member);
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 }) quote!(if #path(#field_expr) { 0 } else { 1 })
} }
}) })
@@ -316,8 +355,7 @@ fn serialize_struct_as_map(
.map(|field| match field.attrs.skip_serializing_if() { .map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1), None => quote!(1),
Some(path) => { Some(path) => {
let ident = field.ident.expect("struct has unnamed fields"); let field_expr = get_member(params, field, &field.member);
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 }) quote!(if #path(#field_expr) { 0 } else { 1 })
} }
}) })
@@ -333,9 +371,9 @@ fn serialize_struct_as_map(
} }
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
assert!(variants.len() as u64 <= u64::from(u32::MAX)); assert!(variants.len() as u64 <= u64::from(u32::max_value()));
let self_var = params.self_var; let self_var = &params.self_var;
let arms: Vec<_> = variants let arms: Vec<_> = variants
.iter() .iter()
@@ -357,9 +395,9 @@ fn serialize_variant(
variant: &Variant, variant: &Variant,
variant_index: u32, variant_index: u32,
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Tokens { ) -> TokenStream {
let this = &params.this; let this = &params.this;
let variant_ident = variant.ident; let variant_ident = &variant.ident;
if variant.attrs.skip_serializing() { if variant.attrs.skip_serializing() {
let skipped_msg = format!( let skipped_msg = format!(
@@ -399,12 +437,9 @@ fn serialize_variant(
} }
} }
Style::Struct => { Style::Struct => {
let fields = variant let members = variant.fields.iter().map(|f| &f.member);
.fields
.iter()
.map(|f| f.ident.expect("struct variant has unnamed fields"));
quote! { quote! {
#this::#variant_ident { #(ref #fields),* } #this::#variant_ident { #(ref #members),* }
} }
} }
}; };
@@ -510,7 +545,7 @@ fn serialize_internally_tagged_variant(
let variant_name = variant.attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name();
let enum_ident_str = params.type_name(); let enum_ident_str = params.type_name();
let variant_ident_str = variant.ident.as_ref(); let variant_ident_str = variant.ident.to_string();
if let Some(path) = variant.attrs.serialize_with() { if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, variant); let ser = wrap_serialize_variant_with(params, path, variant);
@@ -632,15 +667,11 @@ fn serialize_adjacently_tagged_variant(
unreachable!() unreachable!()
} }
} }
Style::Newtype => vec![Ident::new("__field0", Span::call_site())], Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))],
Style::Tuple => (0..variant.fields.len()) Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(&format!("__field{}", i), Span::call_site())) .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site())))
.collect(),
Style::Struct => variant
.fields
.iter()
.map(|f| f.ident.expect("struct variant has unnamed fields"))
.collect(), .collect(),
Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(),
}; };
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
@@ -739,8 +770,23 @@ fn serialize_tuple_variant(
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait);
let len = serialize_stmts.len(); let mut serialized_fields = fields
let let_mut = mut_if(len > 0); .iter()
.enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(|(i, field)| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let field_expr = Ident::new(&format!("__field{}", i), Span::call_site());
quote!(if #path(#field_expr) { 0 } else { 1 })
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context { match context {
TupleVariant::ExternallyTagged { TupleVariant::ExternallyTagged {
@@ -811,10 +857,10 @@ fn serialize_struct_variant<'a>(
let len = serialized_fields let len = serialized_fields
.map(|field| { .map(|field| {
let ident = field.ident.expect("struct has unnamed fields"); let member = &field.member;
match field.attrs.skip_serializing_if() { match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }), Some(path) => quote!(if #path(#member) { 0 } else { 1 }),
None => quote!(1), None => quote!(1),
} }
}) })
@@ -890,7 +936,7 @@ fn serialize_struct_variant_with_flatten<'a>(
} => { } => {
let this = &params.this; let this = &params.this;
let fields_ty = fields.iter().map(|f| &f.ty); let fields_ty = fields.iter().map(|f| &f.ty);
let fields_ident = &fields.iter().map(|f| f.ident).collect::<Vec<_>>(); let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a"); let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a");
@@ -907,7 +953,7 @@ fn serialize_struct_variant_with_flatten<'a>(
where where
__S: _serde::Serializer, __S: _serde::Serializer,
{ {
let (#(#fields_ident,)*) = self.data; let (#(#members,)*) = self.data;
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
__serializer, __serializer,
_serde::export::None)); _serde::export::None));
@@ -922,7 +968,7 @@ fn serialize_struct_variant_with_flatten<'a>(
#variant_index, #variant_index,
#variant_name, #variant_name,
&__EnumFlatten { &__EnumFlatten {
data: (#(#fields_ident,)*), data: (#(#members,)*),
phantom: _serde::export::PhantomData::<#this #ty_generics>, phantom: _serde::export::PhantomData::<#this #ty_generics>,
}) })
} }
@@ -958,10 +1004,11 @@ fn serialize_tuple_struct_visitor(
params: &Parameters, params: &Parameters,
is_enum: bool, is_enum: bool,
tuple_trait: &TupleTrait, tuple_trait: &TupleTrait,
) -> Vec<Tokens> { ) -> Vec<TokenStream> {
fields fields
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
.map(|(i, field)| { .map(|(i, field)| {
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
let id = Ident::new(&format!("__field{}", i), Span::call_site()); let id = Ident::new(&format!("__field{}", i), Span::call_site());
@@ -1005,17 +1052,17 @@ fn serialize_struct_visitor(
params: &Parameters, params: &Parameters,
is_enum: bool, is_enum: bool,
struct_trait: &StructTrait, struct_trait: &StructTrait,
) -> Vec<Tokens> { ) -> Vec<TokenStream> {
fields fields
.iter() .iter()
.filter(|&field| !field.attrs.skip_serializing()) .filter(|&field| !field.attrs.skip_serializing())
.map(|field| { .map(|field| {
let field_ident = field.ident.expect("struct has unnamed field"); let member = &field.member;
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
quote!(#field_ident) quote!(#member)
} else { } else {
get_member(params, field, &Member::Named(field_ident)) get_member(params, field, &member)
}; };
let key_expr = field.attrs.name().serialize_name(); let key_expr = field.attrs.name().serialize_name();
@@ -1069,8 +1116,8 @@ fn wrap_serialize_field_with(
params: &Parameters, params: &Parameters,
field_ty: &syn::Type, field_ty: &syn::Type,
serialize_with: &syn::ExprPath, serialize_with: &syn::ExprPath,
field_expr: &Tokens, field_expr: &TokenStream,
) -> Tokens { ) -> TokenStream {
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)]) wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
} }
@@ -1078,16 +1125,18 @@ fn wrap_serialize_variant_with(
params: &Parameters, params: &Parameters,
serialize_with: &syn::ExprPath, serialize_with: &syn::ExprPath,
variant: &Variant, variant: &Variant,
) -> Tokens { ) -> TokenStream {
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
let field_exprs: Vec<_> = variant let field_exprs: Vec<_> = variant
.fields .fields
.iter() .iter()
.enumerate() .map(|field| {
.map(|(i, field)| { let id = match field.member {
let id = field Member::Named(ref ident) => ident.clone(),
.ident Member::Unnamed(ref member) => {
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::call_site())); Ident::new(&format!("__field{}", member.index), Span::call_site())
}
};
quote!(#id) quote!(#id)
}) })
.collect(); .collect();
@@ -1103,8 +1152,8 @@ fn wrap_serialize_with(
params: &Parameters, params: &Parameters,
serialize_with: &syn::ExprPath, serialize_with: &syn::ExprPath,
field_tys: &[&syn::Type], field_tys: &[&syn::Type],
field_exprs: &[Tokens], field_exprs: &[TokenStream],
) -> Tokens { ) -> TokenStream {
let this = &params.this; let this = &params.this;
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
@@ -1150,7 +1199,7 @@ fn wrap_serialize_with(
// _serde::ser::SerializeStruct::end(__serde_state) // _serde::ser::SerializeStruct::end(__serde_state)
// //
// where we want to omit the `mut` to avoid a warning. // where we want to omit the `mut` to avoid a warning.
fn mut_if(is_mut: bool) -> Option<Tokens> { fn mut_if(is_mut: bool) -> Option<TokenStream> {
if is_mut { if is_mut {
Some(quote!(mut)) Some(quote!(mut))
} else { } else {
@@ -1158,8 +1207,8 @@ fn mut_if(is_mut: bool) -> Option<Tokens> {
} }
} }
fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens { fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream {
let self_var = params.self_var; let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) { match (params.is_remote, field.attrs.getter()) {
(false, None) => quote!(&#self_var.#member), (false, None) => quote!(&#self_var.#member),
(true, None) => { (true, None) => {
@@ -1184,7 +1233,7 @@ enum StructTrait {
} }
impl StructTrait { impl StructTrait {
fn serialize_field(&self, span: Span) -> Tokens { fn serialize_field(&self, span: Span) -> TokenStream {
match *self { match *self {
StructTrait::SerializeMap => { StructTrait::SerializeMap => {
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
@@ -1198,7 +1247,7 @@ impl StructTrait {
} }
} }
fn skip_field(&self, span: Span) -> Option<Tokens> { fn skip_field(&self, span: Span) -> Option<TokenStream> {
match *self { match *self {
StructTrait::SerializeMap => None, StructTrait::SerializeMap => None,
StructTrait::SerializeStruct => { StructTrait::SerializeStruct => {
@@ -1218,7 +1267,7 @@ enum TupleTrait {
} }
impl TupleTrait { impl TupleTrait {
fn serialize_element(&self, span: Span) -> Tokens { fn serialize_element(&self, span: Span) -> TokenStream {
match *self { match *self {
TupleTrait::SerializeTuple => { TupleTrait::SerializeTuple => {
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element)
+3 -4
View File
@@ -1,13 +1,12 @@
use proc_macro2::{Op, Spacing}; use proc_macro2::{Punct, Spacing, TokenStream};
use quote::Tokens;
// None of our generated code requires the `From::from` error conversion // None of our generated code requires the `From::from` error conversion
// performed by the standard library's `try!` macro. With this simplified macro // performed by the standard library's `try!` macro. With this simplified macro
// we see a significant improvement in type checking and borrow checking time of // we see a significant improvement in type checking and borrow checking time of
// the generated code and a slight improvement in binary size. // the generated code and a slight improvement in binary size.
pub fn replacement() -> Tokens { pub fn replacement() -> TokenStream {
// Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it. // Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it.
let dollar = Op::new('$', Spacing::Alone); let dollar = Punct::new('$', Spacing::Alone);
quote! { quote! {
#[allow(unused_macros)] #[allow(unused_macros)]
+2 -2
View File
@@ -15,8 +15,8 @@ include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "README.md", "LICENSE-APACHE",
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
proc-macro2 = "0.3" proc-macro2 = "0.4"
syn = { version = "0.13", default-features = false, features = ["derive", "parsing", "clone-impls"] } syn = { version = "0.14", default-features = false, features = ["derive", "parsing", "clone-impls"] }
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.48" # remember to update html_root_url version = "1.0.61" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
@@ -12,10 +12,10 @@ readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies] [dependencies]
serde = { version = "1.0.16", path = "../serde" } serde = { version = "1.0.60", path = "../serde" }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0.16", path = "../serde", features = ["rc"] } serde = { version = "1.0", path = "../serde", features = ["rc"] }
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
[badges] [badges]
+7 -6
View File
@@ -129,8 +129,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
type Error = Error; type Error = Error;
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf unit seq map identifier ignored_any bytes byte_buf unit seq map identifier ignored_any
} }
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
@@ -599,7 +599,8 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
{ {
match self.variant.take() { match self.variant.take() {
Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(Token::Bytes(variant)) => seed.deserialize(BytesDeserializer { value: variant }) Some(Token::Bytes(variant)) => seed
.deserialize(BytesDeserializer { value: variant })
.map(Some), .map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other), Some(other) => unexpected!(other),
@@ -656,8 +657,8 @@ impl<'de> de::Deserializer<'de> for BytesDeserializer {
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct bytes byte_buf option unit unit_struct newtype_struct seq tuple
map struct enum identifier ignored_any tuple_struct map struct enum identifier ignored_any
} }
} }
+1 -1
View File
@@ -161,7 +161,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.48")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.61")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
+1 -1
View File
@@ -9,7 +9,7 @@ unstable = ["serde/unstable", "compiletest_rs"]
[dev-dependencies] [dev-dependencies]
fnv = "1.0" fnv = "1.0"
proc-macro2 = "0.3" proc-macro2 = "0.4"
rustc-serialize = "0.3.16" rustc-serialize = "0.3.16"
serde = { path = "../serde", features = ["rc"] } serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] } serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
@@ -0,0 +1,15 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
struct S<'de> {
s: &'de str, //~^^ HELP: cannot deserialize when there is a lifetime parameter called 'de
}
@@ -0,0 +1,16 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
struct S {
string: String,
slice: [u8], //~^^^ HELP: cannot deserialize a dynamically sized struct
}
@@ -0,0 +1,20 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(transparent)]
struct S {
//~^^^ HELP: #[serde(transparent)] requires struct to have at most one transparent field
a: u8,
b: u8,
}
fn main() {}
@@ -0,0 +1,22 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
#[serde(transparent)]
struct S {
//~^^^ HELP: #[serde(transparent)] requires at least one field that is neither skipped nor has a default
#[serde(skip)]
a: u8,
#[serde(default)]
b: u8,
}
fn main() {}
@@ -0,0 +1,20 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(transparent)]
struct S {
//~^^^ HELP: #[serde(transparent)] requires at least one field that is not skipped
#[serde(skip)]
a: u8,
}
fn main() {}
+210 -2
View File
@@ -15,6 +15,7 @@ extern crate serde;
use self::serde::de::{self, Unexpected}; use self::serde::de::{self, Unexpected};
use self::serde::{Deserialize, Deserializer, Serialize, Serializer}; use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
extern crate serde_test; extern crate serde_test;
use self::serde_test::{ use self::serde_test::{
@@ -657,6 +658,44 @@ fn test_skip_serializing_struct() {
); );
} }
#[derive(Debug, PartialEq, Serialize)]
struct SkipSerializingTupleStruct<'a, B, C>(
&'a i8,
#[serde(skip_serializing)] B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")] C,
)
where
C: ShouldSkip;
#[test]
fn test_skip_serializing_tuple_struct() {
let a = 1;
assert_ser_tokens(
&SkipSerializingTupleStruct(&a, 2, 3),
&[
Token::TupleStruct {
name: "SkipSerializingTupleStruct",
len: 2,
},
Token::I8(1),
Token::I32(3),
Token::TupleStructEnd,
],
);
assert_ser_tokens(
&SkipSerializingTupleStruct(&a, 2, 123),
&[
Token::TupleStruct {
name: "SkipSerializingTupleStruct",
len: 1,
},
Token::I8(1),
Token::TupleStructEnd,
],
);
}
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
struct SkipStruct<B> { struct SkipStruct<B> {
a: i8, a: i8,
@@ -705,6 +744,11 @@ where
#[serde(skip_serializing_if = "ShouldSkip::should_skip")] #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
c: C, c: C,
}, },
Tuple(
&'a i8,
#[serde(skip_serializing)] B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")] C,
),
} }
#[test] #[test]
@@ -743,6 +787,33 @@ fn test_skip_serializing_enum() {
Token::StructVariantEnd, Token::StructVariantEnd,
], ],
); );
assert_ser_tokens(
&SkipSerializingEnum::Tuple(&a, 2, 3),
&[
Token::TupleVariant {
name: "SkipSerializingEnum",
variant: "Tuple",
len: 2,
},
Token::I8(1),
Token::I32(3),
Token::TupleVariantEnd,
],
);
assert_ser_tokens(
&SkipSerializingEnum::Tuple(&a, 2, 123),
&[
Token::TupleVariant {
name: "SkipSerializingEnum",
variant: "Tuple",
len: 1,
},
Token::I8(1),
Token::TupleVariantEnd,
],
);
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@@ -1230,7 +1301,7 @@ fn test_invalid_length_enum() {
Token::I32(1), Token::I32(1),
Token::TupleVariantEnd, Token::TupleVariantEnd,
], ],
"invalid length 1, expected tuple of 3 elements", "invalid length 1, expected tuple variant InvalidLengthEnum::A with 3 elements",
); );
assert_de_tokens_error::<InvalidLengthEnum>( assert_de_tokens_error::<InvalidLengthEnum>(
&[ &[
@@ -1242,7 +1313,7 @@ fn test_invalid_length_enum() {
Token::I32(1), Token::I32(1),
Token::TupleVariantEnd, Token::TupleVariantEnd,
], ],
"invalid length 1, expected tuple of 2 elements", "invalid length 1, expected tuple variant InvalidLengthEnum::B with 2 elements",
); );
} }
@@ -1992,3 +2063,140 @@ fn test_untagged_enum_containing_flatten() {
], ],
); );
} }
#[test]
fn test_flatten_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Outer {
#[serde(flatten)]
inner: Inner,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum Inner {
Variant { a: i32 },
}
let data = Outer {
inner: Inner::Variant { a: 0 },
};
assert_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::MapEnd,
],
);
}
#[test]
fn test_flatten_option() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Outer {
#[serde(flatten)]
inner1: Option<Inner1>,
#[serde(flatten)]
inner2: Option<Inner2>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Inner1 {
inner1: i32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Inner2 {
inner2: i32,
}
assert_tokens(
&Outer {
inner1: Some(Inner1 { inner1: 1 }),
inner2: Some(Inner2 { inner2: 2 }),
},
&[
Token::Map { len: None },
Token::Str("inner1"),
Token::I32(1),
Token::Str("inner2"),
Token::I32(2),
Token::MapEnd,
],
);
assert_tokens(
&Outer {
inner1: Some(Inner1 { inner1: 1 }),
inner2: None,
},
&[
Token::Map { len: None },
Token::Str("inner1"),
Token::I32(1),
Token::MapEnd,
],
);
assert_tokens(
&Outer {
inner1: None,
inner2: Some(Inner2 { inner2: 2 }),
},
&[
Token::Map { len: None },
Token::Str("inner2"),
Token::I32(2),
Token::MapEnd,
],
);
assert_tokens(
&Outer {
inner1: None,
inner2: None,
},
&[Token::Map { len: None }, Token::MapEnd],
);
}
#[test]
fn test_transparent_struct() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(transparent)]
struct Transparent {
#[serde(skip)]
a: bool,
b: u32,
#[serde(skip)]
c: bool,
d: PhantomData<()>,
}
assert_tokens(
&Transparent {
a: false,
b: 1,
c: false,
d: PhantomData,
},
&[Token::U32(1)],
);
}
#[test]
fn test_transparent_tuple_struct() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(transparent)]
struct Transparent(
#[serde(skip)] bool,
u32,
#[serde(skip)] bool,
PhantomData<()>,
);
assert_tokens(&Transparent(false, 1, false, PhantomData), &[Token::U32(1)]);
}
+67 -3
View File
@@ -17,15 +17,15 @@ use std::ffi::{CString, OsString};
use std::net; use std::net;
use std::num::Wrapping; use std::num::Wrapping;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::{Rc, Weak as RcWeak};
use std::sync::Arc; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
#[cfg(feature = "unstable")] #[cfg(feature = "unstable")]
use std::ffi::CStr; use std::ffi::CStr;
extern crate serde; extern crate serde;
use serde::Deserialize; use serde::{Deserialize, Deserializer};
extern crate fnv; extern crate fnv;
use self::fnv::FnvHasher; use self::fnv::FnvHasher;
@@ -182,6 +182,27 @@ macro_rules! declare_error_tests {
} }
} }
#[derive(Debug)]
struct SkipPartialEq<T>(T);
impl<'de, T> Deserialize<'de> for SkipPartialEq<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(SkipPartialEq)
}
}
impl<T> PartialEq for SkipPartialEq<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
struct IgnoreBase { struct IgnoreBase {
@@ -238,6 +259,27 @@ declare_tests! {
0f32 => &[Token::F32(0.)], 0f32 => &[Token::F32(0.)],
0f64 => &[Token::F64(0.)], 0f64 => &[Token::F64(0.)],
} }
test_small_int_to_128 {
1i128 => &[Token::I8(1)],
1i128 => &[Token::I16(1)],
1i128 => &[Token::I32(1)],
1i128 => &[Token::I64(1)],
1i128 => &[Token::U8(1)],
1i128 => &[Token::U16(1)],
1i128 => &[Token::U32(1)],
1i128 => &[Token::U64(1)],
1u128 => &[Token::I8(1)],
1u128 => &[Token::I16(1)],
1u128 => &[Token::I32(1)],
1u128 => &[Token::I64(1)],
1u128 => &[Token::U8(1)],
1u128 => &[Token::U16(1)],
1u128 => &[Token::U32(1)],
1u128 => &[Token::U64(1)],
}
test_char { test_char {
'a' => &[Token::Char('a')], 'a' => &[Token::Char('a')],
'a' => &[Token::Str("a")], 'a' => &[Token::Str("a")],
@@ -788,11 +830,33 @@ declare_tests! {
Token::Bool(true), Token::Bool(true),
], ],
} }
test_rc_weak_some {
SkipPartialEq(RcWeak::<bool>::new()) => &[
Token::Some,
Token::Bool(true),
],
}
test_rc_weak_none {
SkipPartialEq(RcWeak::<bool>::new()) => &[
Token::None,
],
}
test_arc { test_arc {
Arc::new(true) => &[ Arc::new(true) => &[
Token::Bool(true), Token::Bool(true),
], ],
} }
test_arc_weak_some {
SkipPartialEq(ArcWeak::<bool>::new()) => &[
Token::Some,
Token::Bool(true),
],
}
test_arc_weak_none {
SkipPartialEq(ArcWeak::<bool>::new()) => &[
Token::None,
],
}
test_wrapping { test_wrapping {
Wrapping(1usize) => &[ Wrapping(1usize) => &[
Token::U32(1), Token::U32(1),
+73
View File
@@ -216,6 +216,42 @@ fn test_gen() {
} }
assert::<WithTraits2<X, X>>(); assert::<WithTraits2<X, X>>();
#[derive(Serialize, Deserialize)]
#[serde(bound = "D: SerializeWith + DeserializeWith")]
enum VariantWithTraits1<D, E> {
#[serde(
serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with"
)]
D(D),
#[serde(
serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with",
bound = "E: SerializeWith + DeserializeWith"
)]
E(E),
}
assert::<VariantWithTraits1<X, X>>();
#[derive(Serialize, Deserialize)]
#[serde(bound(serialize = "D: SerializeWith", deserialize = "D: DeserializeWith"))]
enum VariantWithTraits2<D, E> {
#[serde(
serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with"
)]
D(D),
#[serde(
serialize_with = "SerializeWith::serialize_with", bound(serialize = "E: SerializeWith")
)]
#[serde(
deserialize_with = "DeserializeWith::deserialize_with",
bound(deserialize = "E: DeserializeWith")
)]
E(E),
}
assert::<VariantWithTraits2<X, X>>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct CowStr<'a>(Cow<'a, str>); struct CowStr<'a>(Cow<'a, str>);
assert::<CowStr>(); assert::<CowStr>();
@@ -588,6 +624,43 @@ fn test_gen() {
} }
} }
} }
#[derive(Deserialize)]
#[serde(tag = "t", content = "c")]
enum AdjacentlyTaggedVoid {}
#[derive(Serialize, Deserialize)]
enum SkippedVariant<T> {
#[serde(skip)]
#[allow(dead_code)]
T(T),
Unit,
}
assert::<SkippedVariant<X>>();
#[derive(Deserialize)]
struct ImpliciltyBorrowedOption<'a> {
option: std::option::Option<&'a str>,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum UntaggedNewtypeVariantWith {
Newtype(
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
X,
),
}
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct TransparentWith {
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
x: X,
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
+40 -2
View File
@@ -11,11 +11,12 @@ extern crate serde_derive;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::CString; use std::ffi::CString;
use std::mem;
use std::net; use std::net;
use std::num::Wrapping; use std::num::Wrapping;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::{Rc, Weak as RcWeak};
use std::sync::Arc; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
#[cfg(unix)] #[cfg(unix)]
@@ -398,11 +399,41 @@ declare_tests! {
Token::Bool(true), Token::Bool(true),
], ],
} }
test_rc_weak_some {
{
let rc = Rc::new(true);
mem::forget(rc.clone());
Rc::downgrade(&rc)
} => &[
Token::Some,
Token::Bool(true),
],
}
test_rc_weak_none {
RcWeak::<bool>::new() => &[
Token::None,
],
}
test_arc { test_arc {
Arc::new(true) => &[ Arc::new(true) => &[
Token::Bool(true), Token::Bool(true),
], ],
} }
test_arc_weak_some {
{
let arc = Arc::new(true);
mem::forget(arc.clone());
Arc::downgrade(&arc)
} => &[
Token::Some,
Token::Bool(true),
],
}
test_arc_weak_none {
ArcWeak::<bool>::new() => &[
Token::None,
],
}
test_wrapping { test_wrapping {
Wrapping(1usize) => &[ Wrapping(1usize) => &[
Token::U64(1), Token::U64(1),
@@ -555,3 +586,10 @@ fn test_enum_skipped() {
"the enum variant Enum::SkippedMap cannot be serialized", "the enum variant Enum::SkippedMap cannot be serialized",
); );
} }
#[test]
fn test_integer128() {
assert_ser_tokens_error(&1i128, &[], "i128 is not supported");
assert_ser_tokens_error(&1u128, &[], "u128 is not supported");
}