Compare commits

...

102 Commits

Author SHA1 Message Date
David Tolnay 4de20bd48d Release 1.0.59 2018-05-21 03:51:32 -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
David Tolnay 30824e9f61 Release 1.0.48 2018-05-07 10:22:26 -07:00
David Tolnay eecc0870fc Test for pub(restricted) 2018-05-06 23:22:27 -07:00
David Tolnay 6475e73b05 Less horrible logic for missing fields that unconditionally return error 2018-05-06 22:20:35 -07:00
David Tolnay 697234517d Merge pull request #1249 from serde-rs/empty
Fix adjacently tagged empty tuple variant or struct variant
2018-05-06 22:20:27 -07:00
David Tolnay 3cd9d071c2 Fix adjacently tagged empty tuple variant or struct variant 2018-05-06 21:50:40 -07:00
David Tolnay 9dc05c36f0 Release 1.0.47 2018-05-06 21:39:21 -07:00
David Tolnay 972cc06fed Format the flatten tests using rustfmt 0.6.1 2018-05-06 21:38:41 -07:00
David Tolnay 20013464f8 Merge pull request #1248 from serde-rs/flatten
Support flatten in enums
2018-05-06 21:37:32 -07:00
David Tolnay 2009b4da5f Remove old flatten in enum compile-fail test 2018-05-06 21:26:40 -07:00
David Tolnay 0b72c86a35 Add tests for flatten in enums 2018-05-06 21:23:20 -07:00
David Tolnay 94b857057b Support deserializing enums containing flatten 2018-05-06 20:41:02 -07:00
David Tolnay 979df3427b Support serializing enums containing flatten 2018-05-06 20:14:35 -07:00
David Tolnay 978d64993e Allow flatten attribute in enums 2018-05-06 20:14:28 -07:00
David Tolnay 5098609935 Release 1.0.46 2018-05-06 13:44:55 -07:00
David Tolnay 6374467f02 Merge pull request #1245 from serde-rs/flat
Support deserializing a flattened internally tagged enum
2018-05-06 13:43:44 -07:00
David Tolnay 1f9fc61b98 Merge pull request #1246 from serde-rs/internals
Move derive internals into serde_derive crate
2018-05-05 23:58:41 -07:00
David Tolnay 3859f58d9b Move derive internals into serde_derive crate
We can continue to publish serde_derive_internals independently but
serde_derive no longer has a dependency on it. This improves compile
time of serde_derive by 7%.
2018-05-05 23:46:30 -07:00
David Tolnay aac1c65033 Simplify implementation of flattened internally tagged enum
The fact that the tag entry is consumed was only observable if there is
a later flattened map field, at which point the behavior is already
confusing anyway.

    #[derive(Deserialize)]
    struct Example {
        #[serde(flatten)]
        a: InternallyTagged,
        #[serde(flatten)]
        rest: BTreeMap<String, Value>,
    }

Before this simplification the map would receive all the fields of the
internally tagged enum but not its tag, after it receives all the fields
including the tag.
2018-05-05 22:30:46 -07:00
David Tolnay d8120e19bc Support deserializing a flattened internally tagged enum 2018-05-05 21:52:16 -07:00
David Tolnay ed425b3a6f Clean up indentation in VariantAccess doc 2018-05-05 18:40:28 -07:00
David Tolnay d1297deb36 Format where-clauses in serde docs like rustfmt 2018-05-05 18:33:33 -07:00
David Tolnay f263e3fcec Format serde_derive generated where-clauses 2018-05-05 18:24:16 -07:00
David Tolnay 40479336c1 Format serde_test doc where-clauses in the style of rustfmt 2018-05-05 18:20:26 -07:00
David Tolnay 6ca4dd2c4a Add an issue suggestion for documentation improvements 2018-05-05 10:01:54 -07:00
David Tolnay c04c233838 Generalize the help issue type 2018-05-05 10:00:17 -07:00
David Tolnay 175c638fdc Set up some issue templates 2018-05-05 01:45:24 -07:00
David Tolnay 97eff8e875 Format with rustfmt 0.6.1 2018-05-05 00:56:12 -07:00
David Tolnay 47676cdb49 Clean up references to Ident 2018-05-05 00:45:30 -07:00
David Tolnay 93bddb361e Fix toplevel_ref_arg lint 2018-05-05 00:39:26 -07:00
David Tolnay adb1c9540d Remove a layer of wrapping in deserialize_with untagged newtype variant 2018-05-05 00:25:27 -07:00
David Tolnay 0e1d065402 Format with rustfmt 0.6.1 2018-05-05 00:18:21 -07:00
David Tolnay 8c3b52e308 Remove a layer of wrapping in deserialize_with newtype struct 2018-05-05 00:17:00 -07:00
David Tolnay 3f0d3453d8 Release 1.0.45 2018-05-02 15:18:17 -07:00
David Tolnay b27a27ce22 Merge pull request #1241 from serde-rs/pretend
Pretend remote derives are not dead code
2018-05-02 15:17:19 -07:00
David Tolnay 80c0600657 Merge pull request #1243 from serde-rs/ci
Add a CI build on 1.15.0
2018-05-02 15:17:10 -07:00
David Tolnay 77f9e63661 Add a CI build on 1.15.0 2018-05-02 14:29:51 -07:00
David Tolnay b78f434086 Pretend remote derives are not dead code 2018-05-02 14:23:59 -07:00
52 changed files with 2384 additions and 753 deletions
+7
View File
@@ -0,0 +1,7 @@
---
name: Problem
about: Something does not seem right
---
+7
View File
@@ -0,0 +1,7 @@
---
name: Feature request
about: Share how Serde could support your use case better
---
@@ -0,0 +1,7 @@
---
name: Documentation
about: Certainly there is room for improvement
---
+7
View File
@@ -0,0 +1,7 @@
---
name: Help or discussion
about: This is the right place
---
+7
View File
@@ -0,0 +1,7 @@
---
name: Anything else!
about: Whatever is on your mind
---
+1
View File
@@ -5,6 +5,7 @@ cache: cargo
# run builds for all the trains (and more) # run builds for all the trains (and more)
rust: rust:
- 1.13.0 - 1.13.0
- 1.15.0
- stable - stable
- beta - beta
- nightly - nightly
+3 -7
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.44" # remember to update html_root_url version = "1.0.59" # 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"]
+41
View File
@@ -0,0 +1,41 @@
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,
};
// 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");
}
}
-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)
} }
+10 -5
View File
@@ -45,7 +45,8 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
/// } /// }
/// ///
/// impl<'de, T> Visitor<'de> for NthElement<T> /// impl<'de, T> Visitor<'de> for NthElement<T>
/// where T: Deserialize<'de> /// where
/// T: Deserialize<'de>,
/// { /// {
/// type Value = T; /// type Value = T;
/// ///
@@ -54,7 +55,8 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
/// } /// }
/// ///
/// fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> /// fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
/// where A: SeqAccess<'de> /// where
/// A: SeqAccess<'de>,
/// { /// {
/// // Skip over the first `n` elements. /// // Skip over the first `n` elements.
/// for i in 0..self.n { /// for i in 0..self.n {
@@ -82,19 +84,22 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
/// } /// }
/// ///
/// impl<'de, T> DeserializeSeed<'de> for NthElement<T> /// impl<'de, T> DeserializeSeed<'de> for NthElement<T>
/// where T: Deserialize<'de> /// where
/// T: Deserialize<'de>,
/// { /// {
/// type Value = T; /// type Value = T;
/// ///
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> /// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
/// where D: Deserializer<'de> /// where
/// D: Deserializer<'de>,
/// { /// {
/// deserializer.deserialize_seq(self) /// deserializer.deserialize_seq(self)
/// } /// }
/// } /// }
/// ///
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> /// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
/// # where D: Deserializer<'de> /// # where
/// # D: Deserializer<'de>,
/// # { /// # {
/// // Deserialize only the sequence element at index 3 from this deserializer. /// // Deserialize only the sequence element at index 3 from this deserializer.
/// // The element at index 3 is required to be a string. Elements before and /// // The element at index 3 is required to be a string. Elements before and
+120 -90
View File
@@ -8,8 +8,9 @@
use lib::*; use lib::*;
use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess, use de::{
Visitor}; Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess, Visitor,
};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use de::MapAccess; use de::MapAccess;
@@ -31,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,
{ {
@@ -40,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>,
{ {
@@ -59,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,
{ {
@@ -68,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>,
{ {
@@ -109,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>,
{ {
@@ -177,7 +178,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,
{ {
@@ -185,7 +186,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,
{ {
@@ -199,7 +200,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>,
{ {
@@ -222,21 +223,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,
{ {
@@ -246,7 +247,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,
{ {
@@ -268,7 +269,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,
{ {
@@ -277,7 +278,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,
{ {
@@ -285,7 +286,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,
{ {
@@ -299,7 +300,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,
{ {
@@ -318,7 +319,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>,
{ {
@@ -416,7 +417,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>,
{ {
@@ -430,28 +431,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,
{ {
@@ -461,7 +462,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>,
{ {
@@ -506,7 +507,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,
{ {
@@ -514,7 +515,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,
{ {
@@ -522,19 +523,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>,
{ {
@@ -564,7 +573,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,
{ {
@@ -573,7 +582,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>,
{ {
@@ -658,7 +667,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>,
{ {
@@ -770,7 +779,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>,
{ {
@@ -780,7 +789,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>,
{ {
@@ -802,7 +811,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>,
{ {
@@ -828,7 +837,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>,
{ {
@@ -850,7 +859,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>,
{ {
@@ -910,7 +919,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>,
{ {
@@ -927,7 +936,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>,
{ {
@@ -961,7 +970,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>,
{ {
@@ -1330,14 +1339,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,
{ {
@@ -1347,7 +1356,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>,
{ {
@@ -1380,7 +1389,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>,
{ {
@@ -1395,14 +1404,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",
@@ -1413,7 +1423,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>,
{ {
@@ -1463,7 +1473,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>,
{ {
@@ -1473,6 +1483,44 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// 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(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
macro_rules! box_forwarded_impl { macro_rules! box_forwarded_impl {
( (
@@ -1524,7 +1572,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>,
{ {
@@ -1566,7 +1614,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>,
{ {
@@ -1579,7 +1627,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,
{ {
@@ -1590,7 +1638,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,
{ {
@@ -1618,7 +1666,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>,
{ {
@@ -1637,7 +1685,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>,
{ {
@@ -1691,7 +1739,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>,
{ {
@@ -1704,7 +1752,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,
{ {
@@ -1715,7 +1763,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,
{ {
@@ -1743,7 +1791,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>,
{ {
@@ -1762,7 +1810,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>,
{ {
@@ -1835,7 +1883,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>,
{ {
@@ -1848,7 +1896,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,
{ {
@@ -1859,7 +1907,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,
{ {
@@ -1892,7 +1940,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>,
{ {
@@ -1911,7 +1959,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>,
{ {
@@ -1958,30 +2006,12 @@ 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: ty, )+ ) => {
$( $(
#[cfg(feature = "unstable")] #[cfg(feature = "unstable")]
impl<'de> Deserialize<'de> for $T { impl<'de> Deserialize<'de> for $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>,
{ {
@@ -2013,7 +2043,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>,
{ {
@@ -2028,7 +2058,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>,
{ {
@@ -2041,7 +2071,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,
{ {
@@ -2055,7 +2085,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,
{ {
@@ -2066,7 +2096,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,
{ {
@@ -2100,7 +2130,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>,
{ {
@@ -2124,7 +2154,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>,
{ {
+74 -36
View File
@@ -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,7 +97,6 @@
//! - Path //! - Path
//! - PathBuf //! - PathBuf
//! - Range\<T\> //! - Range\<T\>
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable) //! - num::NonZero* (unstable)
//! - **Net types**: //! - **Net types**:
//! - IpAddr //! - IpAddr
@@ -172,7 +170,8 @@ macro_rules! declare_error_trait {
/// ///
/// impl<'de> Deserialize<'de> for IpAddr { /// impl<'de> Deserialize<'de> for IpAddr {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> /// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de> /// where
/// D: Deserializer<'de>,
/// { /// {
/// let s = try!(String::deserialize(deserializer)); /// let s = try!(String::deserialize(deserializer));
/// s.parse().map_err(de::Error::custom) /// s.parse().map_err(de::Error::custom)
@@ -306,7 +305,8 @@ declare_error_trait!(Error: Sized + Debug + Display);
/// # } /// # }
/// # /// #
/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> /// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
/// where E: de::Error /// where
/// E: de::Error,
/// { /// {
/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) /// Err(de::Error::invalid_type(Unexpected::Bool(v), &self))
/// } /// }
@@ -430,7 +430,8 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// # } /// # }
/// # /// #
/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> /// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
/// where E: de::Error /// where
/// E: de::Error,
/// { /// {
/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) /// Err(de::Error::invalid_type(Unexpected::Bool(v), &self))
/// } /// }
@@ -443,7 +444,8 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// # use serde::de::{self, Unexpected}; /// # use serde::de::{self, Unexpected};
/// # /// #
/// # fn example<E>() -> Result<(), E> /// # fn example<E>() -> Result<(), E>
/// # where E: de::Error /// # where
/// # E: de::Error,
/// # { /// # {
/// # let v = true; /// # let v = true;
/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer")); /// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer"));
@@ -557,11 +559,13 @@ pub trait Deserialize<'de>: Sized {
/// # /// #
/// # trait Ignore { /// # trait Ignore {
/// fn from_str<'a, T>(s: &'a str) -> Result<T> /// fn from_str<'a, T>(s: &'a str) -> Result<T>
/// where T: Deserialize<'a>; /// where
/// T: Deserialize<'a>;
/// ///
/// fn from_reader<R, T>(rdr: R) -> Result<T> /// fn from_reader<R, T>(rdr: R) -> Result<T>
/// where R: Read, /// where
/// T: DeserializeOwned; /// R: Read,
/// T: DeserializeOwned;
/// # } /// # }
/// ``` /// ```
pub trait DeserializeOwned: for<'de> Deserialize<'de> {} pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
@@ -637,7 +641,8 @@ where
/// struct ExtendVec<'a, T: 'a>(&'a mut Vec<T>); /// struct ExtendVec<'a, T: 'a>(&'a mut Vec<T>);
/// ///
/// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> /// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T>
/// where T: Deserialize<'de> /// where
/// T: Deserialize<'de>,
/// { /// {
/// // The return type of the `deserialize` method. This implementation /// // The return type of the `deserialize` method. This implementation
/// // appends onto an existing vector but does not create any new data /// // appends onto an existing vector but does not create any new data
@@ -645,14 +650,16 @@ where
/// type Value = (); /// type Value = ();
/// ///
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> /// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
/// where D: Deserializer<'de> /// where
/// D: Deserializer<'de>,
/// { /// {
/// // Visitor implementation that will walk an inner array of the JSON /// // Visitor implementation that will walk an inner array of the JSON
/// // input. /// // input.
/// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec<T>); /// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec<T>);
/// ///
/// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> /// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T>
/// where T: Deserialize<'de> /// where
/// T: Deserialize<'de>,
/// { /// {
/// type Value = (); /// type Value = ();
/// ///
@@ -661,7 +668,8 @@ where
/// } /// }
/// ///
/// fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error> /// fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
/// where A: SeqAccess<'de> /// where
/// A: SeqAccess<'de>,
/// { /// {
/// // Visit each element in the inner array and push it onto /// // Visit each element in the inner array and push it onto
/// // the existing vector. /// // the existing vector.
@@ -680,7 +688,8 @@ where
/// struct FlattenedVecVisitor<T>(PhantomData<T>); /// struct FlattenedVecVisitor<T>(PhantomData<T>);
/// ///
/// impl<'de, T> Visitor<'de> for FlattenedVecVisitor<T> /// impl<'de, T> Visitor<'de> for FlattenedVecVisitor<T>
/// where T: Deserialize<'de> /// where
/// T: Deserialize<'de>,
/// { /// {
/// // This Visitor constructs a single Vec<T> to hold the flattened /// // This Visitor constructs a single Vec<T> to hold the flattened
/// // contents of the inner arrays. /// // contents of the inner arrays.
@@ -691,7 +700,8 @@ where
/// } /// }
/// ///
/// fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error> /// fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error>
/// where A: SeqAccess<'de> /// where
/// A: SeqAccess<'de>,
/// { /// {
/// // Create a single Vec to hold the flattened contents. /// // Create a single Vec to hold the flattened contents.
/// let mut vec = Vec::new(); /// let mut vec = Vec::new();
@@ -707,7 +717,8 @@ where
/// } /// }
/// ///
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> /// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
/// # where D: Deserializer<'de> /// # where
/// # D: Deserializer<'de>,
/// # { /// # {
/// let visitor = FlattenedVecVisitor(PhantomData); /// let visitor = FlattenedVecVisitor(PhantomData);
/// let flattened: Vec<u64> = deserializer.deserialize_seq(visitor)?; /// let flattened: Vec<u64> = deserializer.deserialize_seq(visitor)?;
@@ -1092,7 +1103,8 @@ pub trait Deserializer<'de>: Sized {
/// ///
/// impl<'de> Deserialize<'de> for Timestamp { /// impl<'de> Deserialize<'de> for Timestamp {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> /// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de> /// where
/// D: Deserializer<'de>,
/// { /// {
/// if deserializer.is_human_readable() { /// if deserializer.is_human_readable() {
/// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z". /// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z".
@@ -1143,7 +1155,8 @@ pub trait Deserializer<'de>: Sized {
/// } /// }
/// ///
/// fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> /// fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
/// where E: de::Error /// where
/// E: de::Error,
/// { /// {
/// if s.len() >= self.min { /// if s.len() >= self.min {
/// Ok(s.to_owned()) /// Ok(s.to_owned())
@@ -1514,6 +1527,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(())
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1823,15 +1845,18 @@ pub trait VariantAccess<'de>: Sized {
/// } /// }
/// # /// #
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
/// # where T: DeserializeSeed<'de> /// # where
/// # T: DeserializeSeed<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # } /// # }
/// ``` /// ```
@@ -1858,7 +1883,8 @@ pub trait VariantAccess<'de>: Sized {
/// # } /// # }
/// # /// #
/// fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error> /// fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
/// where T: DeserializeSeed<'de> /// where
/// T: DeserializeSeed<'de>,
/// { /// {
/// // What the data actually contained; suppose it is a unit variant. /// // What the data actually contained; suppose it is a unit variant.
/// let unexp = Unexpected::UnitVariant; /// let unexp = Unexpected::UnitVariant;
@@ -1866,11 +1892,13 @@ pub trait VariantAccess<'de>: Sized {
/// } /// }
/// # /// #
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # } /// # }
/// ``` /// ```
@@ -1911,13 +1939,17 @@ pub trait VariantAccess<'de>: Sized {
/// # } /// # }
/// # /// #
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
/// # where T: DeserializeSeed<'de> /// # where
/// # T: DeserializeSeed<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// fn tuple_variant<V>(self, /// fn tuple_variant<V>(
/// _len: usize, /// self,
/// _visitor: V) -> Result<V::Value, Self::Error> /// _len: usize,
/// where V: Visitor<'de> /// _visitor: V,
/// ) -> Result<V::Value, Self::Error>
/// where
/// V: Visitor<'de>,
/// { /// {
/// // What the data actually contained; suppose it is a unit variant. /// // What the data actually contained; suppose it is a unit variant.
/// let unexp = Unexpected::UnitVariant; /// let unexp = Unexpected::UnitVariant;
@@ -1925,7 +1957,8 @@ pub trait VariantAccess<'de>: Sized {
/// } /// }
/// # /// #
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # } /// # }
/// ``` /// ```
@@ -1953,17 +1986,22 @@ pub trait VariantAccess<'de>: Sized {
/// # } /// # }
/// # /// #
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
/// # where T: DeserializeSeed<'de> /// # where
/// # T: DeserializeSeed<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// fn struct_variant<V>(self, /// fn struct_variant<V>(
/// _fields: &'static [&'static str], /// self,
/// _visitor: V) -> Result<V::Value, Self::Error> /// _fields: &'static [&'static str],
/// where V: Visitor<'de> /// _visitor: V,
/// ) -> Result<V::Value, Self::Error>
/// where
/// V: Visitor<'de>,
/// { /// {
/// // What the data actually contained; suppose it is a unit variant. /// // What the data actually contained; suppose it is a unit variant.
/// let unexp = Unexpected::UnitVariant; /// let unexp = Unexpected::UnitVariant;
+6 -10
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.44")] #![doc(html_root_url = "https://docs.rs/serde/1.0.59")]
// 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
@@ -179,14 +179,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};
@@ -213,10 +213,6 @@ mod lib {
#[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")] #[cfg(feature = "unstable")]
pub use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; pub use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
} }
+8 -4
View File
@@ -31,14 +31,16 @@
/// # type Error = value::Error; /// # type Error = value::Error;
/// # /// #
/// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error> /// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
/// # where V: Visitor<'de> /// # where
/// # V: Visitor<'de>,
/// # { /// # {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # /// #
/// #[inline] /// #[inline]
/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> /// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
/// where V: Visitor<'de> /// where
/// V: Visitor<'de>,
/// { /// {
/// self.deserialize_any(visitor) /// self.deserialize_any(visitor)
/// } /// }
@@ -69,7 +71,8 @@
/// # type Error = value::Error; /// # type Error = value::Error;
/// # /// #
/// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> /// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
/// where V: Visitor<'de> /// where
/// V: Visitor<'de>,
/// { /// {
/// /* ... */ /// /* ... */
/// # let _ = visitor; /// # let _ = visitor;
@@ -105,7 +108,8 @@
/// # type Error = value::Error; /// # type Error = value::Error;
/// # /// #
/// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error> /// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error>
/// # where W: Visitor<'q> /// # where
/// # W: Visitor<'q>,
/// # { /// # {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
+131 -21
View File
@@ -14,10 +14,11 @@ use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Vi
use de::{MapAccess, Unexpected}; use de::{MapAccess, Unexpected};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer, EnumDeserializer, pub use self::content::{
InternallyTaggedUnitVisitor, TagContentOtherField, Content, ContentDeserializer, ContentRefDeserializer, EnumDeserializer,
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor, InternallyTaggedUnitVisitor, TagContentOtherField, TagContentOtherFieldVisitor,
TaggedContentVisitor, UntaggedUnitVisitor}; TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor,
};
/// If the missing field is of type `Option<T>` then treat is as `None`, /// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error. /// otherwise it is an error.
@@ -229,8 +230,10 @@ mod content {
use lib::*; use lib::*;
use super::size_hint; use super::size_hint;
use de::{self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, MapAccess, use de::{
SeqAccess, Unexpected, Visitor}; self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, MapAccess,
SeqAccess, Unexpected, Visitor,
};
/// Used from generated code to buffer the contents of the Deserializer when /// Used from generated code to buffer the contents of the Deserializer when
/// deserializing untagged enums and internally tagged enums. /// deserializing untagged enums and internally tagged enums.
@@ -273,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,
} }
} }
@@ -1420,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)),
} }
} }
@@ -2120,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)),
} }
} }
@@ -2314,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),
} }
@@ -2637,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
@@ -2644,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>(
@@ -2707,10 +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 where
byte_buf option unit unit_struct seq tuple tuple_struct identifier V: Visitor<'de>,
ignored_any {
match visitor.__private_visit_untagged_option(self) {
Ok(value) => Ok(value),
Err(()) => Self::deserialize_other(),
}
}
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()
} }
} }
@@ -2754,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 {
@@ -2783,3 +2850,46 @@ where
} }
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E>
where
E: Error,
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
Some(item) => {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
let (ref key, ref content) = *item.as_ref().unwrap();
self.pending = Some(content);
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
}
}
+8 -6
View File
@@ -11,8 +11,9 @@ use lib::*;
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{Content, ContentSerializer, SerializeStructVariantAsMapValue, use self::content::{
SerializeTupleVariantAsMapValue}; Content, ContentSerializer, SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue,
};
/// Used to check that serde(getter) attributes return the expected type. /// Used to check that serde(getter) attributes return the expected type.
/// Not public API. /// Not public API.
@@ -946,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()));
@@ -1121,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> {
+27 -6
View File
@@ -374,20 +374,40 @@ 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, )+ ) => {
$( $(
@@ -515,7 +535,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()));
+4 -2
View File
@@ -10,8 +10,10 @@
use lib::*; use lib::*;
use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, use ser::{
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}; self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
};
/// Helper type for implementing a `Serializer` that does not support /// Helper type for implementing a `Serializer` that does not support
/// serializing one of the compound types. /// serializing one of the compound types.
+110 -60
View File
@@ -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,7 +92,6 @@
//! - Path //! - Path
//! - PathBuf //! - PathBuf
//! - Range\<T\> //! - Range\<T\>
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable) //! - num::NonZero* (unstable)
//! - **Net types**: //! - **Net types**:
//! - IpAddr //! - IpAddr
@@ -152,7 +150,8 @@ macro_rules! declare_error_trait {
/// ///
/// impl Serialize for Path { /// impl Serialize for Path {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match self.to_str() { /// match self.to_str() {
/// Some(s) => serializer.serialize_str(s), /// Some(s) => serializer.serialize_str(s),
@@ -223,7 +222,8 @@ pub trait Serialize {
/// // This is what #[derive(Serialize)] would generate. /// // This is what #[derive(Serialize)] would generate.
/// impl Serialize for Person { /// impl Serialize for Person {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut s = serializer.serialize_struct("Person", 3)?; /// let mut s = serializer.serialize_struct("Person", 3)?;
/// s.serialize_field("name", &self.name)?; /// s.serialize_field("name", &self.name)?;
@@ -377,7 +377,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for bool { /// impl Serialize for bool {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_bool(*self) /// serializer.serialize_bool(*self)
/// } /// }
@@ -403,7 +404,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for i8 { /// impl Serialize for i8 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_i8(*self) /// serializer.serialize_i8(*self)
/// } /// }
@@ -429,7 +431,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for i16 { /// impl Serialize for i16 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_i16(*self) /// serializer.serialize_i16(*self)
/// } /// }
@@ -455,7 +458,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for i32 { /// impl Serialize for i32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_i32(*self) /// serializer.serialize_i32(*self)
/// } /// }
@@ -477,7 +481,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for i64 { /// impl Serialize for i64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_i64(*self) /// serializer.serialize_i64(*self)
/// } /// }
@@ -503,7 +508,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for u8 { /// impl Serialize for u8 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_u8(*self) /// serializer.serialize_u8(*self)
/// } /// }
@@ -529,7 +535,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for u16 { /// impl Serialize for u16 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_u16(*self) /// serializer.serialize_u16(*self)
/// } /// }
@@ -555,7 +562,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for u32 { /// impl Serialize for u32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_u32(*self) /// serializer.serialize_u32(*self)
/// } /// }
@@ -577,7 +585,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for u64 { /// impl Serialize for u64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_u64(*self) /// serializer.serialize_u64(*self)
/// } /// }
@@ -603,7 +612,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for f32 { /// impl Serialize for f32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_f32(*self) /// serializer.serialize_f32(*self)
/// } /// }
@@ -625,7 +635,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for f64 { /// impl Serialize for f64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_f64(*self) /// serializer.serialize_f64(*self)
/// } /// }
@@ -650,7 +661,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for char { /// impl Serialize for char {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_char(*self) /// serializer.serialize_char(*self)
/// } /// }
@@ -672,7 +684,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for str { /// impl Serialize for str {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_str(self) /// serializer.serialize_str(self)
/// } /// }
@@ -737,10 +750,12 @@ pub trait Serializer: Sized {
/// # use Option::{Some, None}; /// # use Option::{Some, None};
/// # /// #
/// impl<T> Serialize for Option<T> /// impl<T> Serialize for Option<T>
/// where T: Serialize /// where
/// 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 S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// Some(ref value) => serializer.serialize_some(value), /// Some(ref value) => serializer.serialize_some(value),
@@ -770,10 +785,12 @@ pub trait Serializer: Sized {
/// # use Option::{Some, None}; /// # use Option::{Some, None};
/// # /// #
/// impl<T> Serialize for Option<T> /// impl<T> Serialize for Option<T>
/// where T: Serialize /// where
/// 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 S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// Some(ref value) => serializer.serialize_some(value), /// Some(ref value) => serializer.serialize_some(value),
@@ -802,7 +819,8 @@ pub trait Serializer: Sized {
/// # /// #
/// impl Serialize for () { /// impl Serialize for () {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_unit() /// serializer.serialize_unit()
/// } /// }
@@ -823,7 +841,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Nothing { /// impl Serialize for Nothing {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_unit_struct("Nothing") /// serializer.serialize_unit_struct("Nothing")
/// } /// }
@@ -847,7 +866,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::A => serializer.serialize_unit_variant("E", 0, "A"), /// E::A => serializer.serialize_unit_variant("E", 0, "A"),
@@ -876,7 +896,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Millimeters { /// impl Serialize for Millimeters {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.serialize_newtype_struct("Millimeters", &self.0) /// serializer.serialize_newtype_struct("Millimeters", &self.0)
/// } /// }
@@ -906,7 +927,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::M(ref s) => serializer.serialize_newtype_variant("E", 0, "M", s), /// E::M(ref s) => serializer.serialize_newtype_variant("E", 0, "M", s),
@@ -956,10 +978,12 @@ pub trait Serializer: Sized {
/// use serde::ser::{Serialize, Serializer, SerializeSeq}; /// use serde::ser::{Serialize, Serializer, SerializeSeq};
/// ///
/// impl<T> Serialize for Vec<T> /// impl<T> Serialize for Vec<T>
/// where T: Serialize /// where
/// 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 S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut seq = serializer.serialize_seq(Some(self.len()))?; /// let mut seq = serializer.serialize_seq(Some(self.len()))?;
/// for element in self { /// for element in self {
@@ -988,12 +1012,14 @@ pub trait Serializer: Sized {
/// # struct Tuple3<A, B, C>(A, B, C); /// # struct Tuple3<A, B, C>(A, B, C);
/// # /// #
/// # impl<A, B, C> Serialize for Tuple3<A, B, C> /// # impl<A, B, C> Serialize for Tuple3<A, B, C>
/// where A: Serialize, /// where
/// B: Serialize, /// A: Serialize,
/// C: Serialize /// B: Serialize,
/// C: Serialize,
/// { /// {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut tup = serializer.serialize_tuple(3)?; /// let mut tup = serializer.serialize_tuple(3)?;
/// tup.serialize_element(&self.0)?; /// tup.serialize_element(&self.0)?;
@@ -1012,7 +1038,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Vram { /// impl Serialize for Vram {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut seq = serializer.serialize_tuple(VRAM_SIZE)?; /// let mut seq = serializer.serialize_tuple(VRAM_SIZE)?;
/// for element in &self.0[..] { /// for element in &self.0[..] {
@@ -1038,7 +1065,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Rgb { /// impl Serialize for Rgb {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; /// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?;
/// ts.serialize_field(&self.0)?; /// ts.serialize_field(&self.0)?;
@@ -1072,7 +1100,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::T(ref a, ref b) => { /// E::T(ref a, ref b) => {
@@ -1130,11 +1159,13 @@ pub trait Serializer: Sized {
/// use serde::ser::{Serialize, Serializer, SerializeMap}; /// use serde::ser::{Serialize, Serializer, SerializeMap};
/// ///
/// impl<K, V> Serialize for HashMap<K, V> /// impl<K, V> Serialize for HashMap<K, V>
/// where K: Serialize, /// where
/// V: Serialize /// K: Serialize,
/// V: Serialize,
/// { /// {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut map = serializer.serialize_map(Some(self.len()))?; /// let mut map = serializer.serialize_map(Some(self.len()))?;
/// for (k, v) in self { /// for (k, v) in self {
@@ -1164,7 +1195,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Rgb { /// impl Serialize for Rgb {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut rgb = serializer.serialize_struct("Rgb", 3)?; /// let mut rgb = serializer.serialize_struct("Rgb", 3)?;
/// rgb.serialize_field("r", &self.r)?; /// rgb.serialize_field("r", &self.r)?;
@@ -1197,7 +1229,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::S { ref r, ref g, ref b } => { /// E::S { ref r, ref g, ref b } => {
@@ -1234,7 +1267,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for SecretlyOneHigher { /// impl Serialize for SecretlyOneHigher {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.collect_seq(self.data.iter().map(|x| x + 1)) /// serializer.collect_seq(self.data.iter().map(|x| x + 1))
/// } /// }
@@ -1272,7 +1306,8 @@ pub trait Serializer: Sized {
/// // Serializes as a map in which the values are all unit. /// // Serializes as a map in which the values are all unit.
/// impl Serialize for MapToUnit { /// impl Serialize for MapToUnit {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.collect_map(self.keys.iter().map(|k| (k, ()))) /// serializer.collect_map(self.keys.iter().map(|k| (k, ())))
/// } /// }
@@ -1312,7 +1347,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for DateTime { /// impl Serialize for DateTime {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.collect_str(&format_args!("{:?}{:?}", /// serializer.collect_str(&format_args!("{:?}{:?}",
/// self.naive_local(), /// self.naive_local(),
@@ -1352,7 +1388,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for DateTime { /// impl Serialize for DateTime {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// serializer.collect_str(&format_args!("{:?}{:?}", /// serializer.collect_str(&format_args!("{:?}{:?}",
/// self.naive_local(), /// self.naive_local(),
@@ -1393,7 +1430,8 @@ pub trait Serializer: Sized {
/// ///
/// impl Serialize for Timestamp { /// impl Serialize for Timestamp {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// if serializer.is_human_readable() { /// if serializer.is_human_readable() {
/// // Serialize to a human-readable string "2015-05-15T17:01:00Z". /// // Serialize to a human-readable string "2015-05-15T17:01:00Z".
@@ -1442,10 +1480,12 @@ pub trait Serializer: Sized {
/// use serde::ser::{Serialize, Serializer, SerializeSeq}; /// use serde::ser::{Serialize, Serializer, SerializeSeq};
/// ///
/// impl<T> Serialize for Vec<T> /// impl<T> Serialize for Vec<T>
/// where T: Serialize /// where
/// 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 S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut seq = serializer.serialize_seq(Some(self.len()))?; /// let mut seq = serializer.serialize_seq(Some(self.len()))?;
/// for element in self { /// for element in self {
@@ -1485,12 +1525,14 @@ pub trait SerializeSeq {
/// # struct Tuple3<A, B, C>(A, B, C); /// # struct Tuple3<A, B, C>(A, B, C);
/// # /// #
/// # impl<A, B, C> Serialize for Tuple3<A, B, C> /// # impl<A, B, C> Serialize for Tuple3<A, B, C>
/// where A: Serialize, /// where
/// B: Serialize, /// A: Serialize,
/// C: Serialize /// B: Serialize,
/// C: Serialize,
/// { /// {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut tup = serializer.serialize_tuple(3)?; /// let mut tup = serializer.serialize_tuple(3)?;
/// tup.serialize_element(&self.0)?; /// tup.serialize_element(&self.0)?;
@@ -1529,10 +1571,12 @@ pub trait SerializeSeq {
/// # } /// # }
/// # /// #
/// # impl<T> Serialize for Array<T> /// # impl<T> Serialize for Array<T>
/// where T: Serialize /// where
/// 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 S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut seq = serializer.serialize_tuple(16)?; /// let mut seq = serializer.serialize_tuple(16)?;
/// for element in self { /// for element in self {
@@ -1567,7 +1611,8 @@ pub trait SerializeTuple {
/// ///
/// impl Serialize for Rgb { /// impl Serialize for Rgb {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; /// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?;
/// ts.serialize_field(&self.0)?; /// ts.serialize_field(&self.0)?;
@@ -1605,7 +1650,8 @@ pub trait SerializeTupleStruct {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::T(ref a, ref b) => { /// E::T(ref a, ref b) => {
@@ -1666,11 +1712,13 @@ pub trait SerializeTupleVariant {
/// use serde::ser::{Serialize, Serializer, SerializeMap}; /// use serde::ser::{Serialize, Serializer, SerializeMap};
/// ///
/// impl<K, V> Serialize for HashMap<K, V> /// impl<K, V> Serialize for HashMap<K, V>
/// where K: Serialize, /// where
/// V: Serialize /// K: Serialize,
/// V: Serialize,
/// { /// {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut map = serializer.serialize_map(Some(self.len()))?; /// let mut map = serializer.serialize_map(Some(self.len()))?;
/// for (k, v) in self { /// for (k, v) in self {
@@ -1754,7 +1802,8 @@ pub trait SerializeMap {
/// ///
/// impl Serialize for Rgb { /// impl Serialize for Rgb {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// let mut rgb = serializer.serialize_struct("Rgb", 3)?; /// let mut rgb = serializer.serialize_struct("Rgb", 3)?;
/// rgb.serialize_field("r", &self.r)?; /// rgb.serialize_field("r", &self.r)?;
@@ -1802,7 +1851,8 @@ pub trait SerializeStruct {
/// ///
/// impl Serialize for E { /// impl Serialize for E {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer /// where
/// S: Serializer,
/// { /// {
/// match *self { /// match *self {
/// E::S { ref r, ref g, ref b } => { /// E::S { ref r, ref g, ref b } => {
+4 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.44" # remember to update html_root_url version = "1.0.59" # 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,10 +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"
serde_derive_internals = { version = "=0.23.1", default-features = false, path = "../serde_derive_internals" } syn = { version = "0.14", features = ["visit"] }
syn = { version = "0.13", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+37 -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,7 @@ 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 +185,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 +247,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 +257,10 @@ 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 +280,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");
+328 -200
View File
File diff suppressed because it is too large Load Diff
+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 quote::ToTokens;
use syn::token; use syn::token;
use proc_macro2::TokenStream;
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,
@@ -6,11 +6,11 @@
// 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 attr; use internals::attr;
use check; use internals::check;
use internals::{Ctxt, Derive};
use syn; use syn;
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use Ctxt;
pub struct Container<'a> { pub struct Container<'a> {
pub ident: syn::Ident, pub ident: syn::Ident,
@@ -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,
@@ -6,6 +6,7 @@
// 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 internals::Ctxt;
use proc_macro2::{Group, Span, TokenStream, TokenTree}; use proc_macro2::{Group, Span, TokenStream, TokenTree};
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::str::FromStr; use std::str::FromStr;
@@ -15,7 +16,6 @@ use syn::synom::{ParseError, Synom};
use syn::Ident; use syn::Ident;
use syn::Meta::{List, NameValue, Word}; use syn::Meta::{List, NameValue, Word};
use syn::NestedMeta::{Literal, Meta}; use syn::NestedMeta::{Literal, Meta};
use Ctxt;
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints // This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
@@ -25,7 +25,7 @@ use Ctxt;
// user will see errors simultaneously for all bad attributes in the crate // user will see errors simultaneously for all bad attributes in the crate
// rather than just the first. // rather than just the first.
pub use case::RenameRule; pub use internals::case::RenameRule;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Attr<'c, T> { struct Attr<'c, T> {
@@ -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,
@@ -167,6 +168,7 @@ pub enum Identifier {
} }
impl Identifier { impl Identifier {
#[cfg(feature = "deserialize_in_place")]
pub fn is_some(self) -> bool { pub fn is_some(self) -> bool {
match self { match self {
Identifier::No => false, Identifier::No => false,
@@ -180,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");
@@ -199,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());
} }
@@ -215,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!(
@@ -227,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(_),
.. ..
@@ -248,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(_),
@@ -267,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);
@@ -283,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();
} }
@@ -294,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());
@@ -308,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());
@@ -323,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);
} }
@@ -347,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();
} }
@@ -375,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),
@@ -397,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
} }
@@ -526,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,
@@ -541,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");
@@ -551,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());
} }
@@ -567,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!(
@@ -579,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
@@ -614,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);
} }
} }
@@ -662,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(),
@@ -688,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
} }
@@ -725,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.
@@ -737,6 +789,15 @@ pub enum Default {
Path(syn::ExprPath), Path(syn::ExprPath),
} }
impl Default {
pub fn is_none(&self) -> bool {
match *self {
Default::None => true,
Default::Default | Default::Path(_) => false,
}
}
}
impl Field { impl Field {
/// Extract out the `#[serde(...)]` attributes from a struct field. /// Extract out the `#[serde(...)]` attributes from a struct field.
pub fn from_ast( pub fn from_ast(
@@ -766,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
@@ -781,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());
} }
@@ -796,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
@@ -865,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);
@@ -881,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);
} }
@@ -890,7 +949,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.as_ref(), &m.lit) parse_lit_into_lifetimes(cx, &m.ident, &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 {
@@ -908,13 +967,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();
} }
@@ -991,7 +1050,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);
@@ -1019,6 +1078,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,
} }
} }
@@ -1078,6 +1138,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>);
@@ -1090,21 +1158,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);
} }
} }
@@ -1153,8 +1222,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 {
@@ -1168,7 +1237,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())))
@@ -1176,7 +1245,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));
@@ -1186,8 +1255,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));
@@ -1202,7 +1271,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(|_| {
@@ -1218,7 +1287,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));
@@ -1239,7 +1308,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));
} }
} }
@@ -1253,6 +1322,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.
// //
@@ -1300,6 +1377,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.
// //
@@ -1320,7 +1422,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,
@@ -1346,7 +1448,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()
} }
@@ -6,19 +6,21 @@
// 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 ast::{Container, Data, Style}; use internals::ast::{Container, Data, Field, Style};
use attr::{EnumTag, Identifier}; use internals::attr::{EnumTag, Identifier};
use 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`
@@ -44,43 +46,49 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
/// Flattening has some restrictions we can test. /// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) { fn check_flatten(cx: &Ctxt, cont: &Container) {
match cont.data { match cont.data {
Data::Enum(_) => { Data::Enum(ref variants) => {
if cont.attrs.has_flatten() { for variant in variants {
cx.error("#[serde(flatten)] cannot be used within enums"); for field in &variant.fields {
} check_flatten_field(cx, variant.style, field);
}
Data::Struct(style, _) => {
for field in cont.data.all_fields() {
if !field.attrs.flatten() {
continue;
}
match style {
Style::Tuple => {
cx.error("#[serde(flatten)] cannot be used on tuple structs");
}
Style::Newtype => {
cx.error("#[serde(flatten)] cannot be used on newtype structs");
}
_ => {}
}
if field.attrs.skip_serializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing)]",
);
} else if field.attrs.skip_serializing_if().is_some() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing_if = \"...\")]",
);
} else if field.attrs.skip_deserializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_deserializing)]",
);
} }
} }
} }
Data::Struct(style, ref fields) => {
for field in fields {
check_flatten_field(cx, style, field);
}
}
}
}
fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
if !field.attrs.flatten() {
return;
}
match style {
Style::Tuple => {
cx.error("#[serde(flatten)] cannot be used on tuple structs");
}
Style::Newtype => {
cx.error("#[serde(flatten)] cannot be used on newtype structs");
}
_ => {}
}
if field.attrs.skip_serializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing)]",
);
} else if field.attrs.skip_serializing_if().is_some() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing_if = \"...\")]",
);
} else if field.attrs.skip_deserializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_deserializing)]",
);
} }
} }
@@ -165,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
)); ));
} }
@@ -183,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
)); ));
} }
} }
@@ -198,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
)); ));
} }
} }
@@ -276,3 +278,76 @@ 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(),
}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017 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.
pub mod ast;
pub mod attr;
mod ctxt;
pub use self::ctxt::Ctxt;
mod case;
mod check;
#[derive(Copy, Clone)]
pub enum Derive {
Serialize,
Deserialize,
}
+18 -4
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.44")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.59")]
#![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"]
@@ -35,11 +48,11 @@ extern crate quote;
#[macro_use] #[macro_use]
extern crate syn; extern crate syn;
extern crate serde_derive_internals as internals;
extern crate proc_macro; extern crate proc_macro;
extern crate proc_macro2; extern crate proc_macro2;
mod internals;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::DeriveInput; use syn::DeriveInput;
@@ -49,6 +62,7 @@ mod bound;
mod fragment; mod fragment;
mod de; mod de;
mod pretend;
mod ser; mod ser;
mod try; mod try;
+140
View File
@@ -0,0 +1,140 @@
use proc_macro2::{Span, TokenStream};
use syn::Ident;
use internals::ast::{Container, Data, Field, Style};
// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
// never has its fields referenced and an enum annotated with remote derive
// never has its variants constructed.
//
// warning: field is never used: `i`
// --> src/main.rs:4:20
// |
// 4 | struct StructDef { i: i32 }
// | ^^^^^^
//
// warning: variant is never constructed: `V`
// --> src/main.rs:8:16
// |
// 8 | enum EnumDef { V }
// | ^
//
pub fn pretend_used(cont: &Container) -> TokenStream {
let pretend_fields = pretend_fields_used(cont);
let pretend_variants = pretend_variants_used(cont);
quote! {
#pretend_fields
#pretend_variants
}
}
// For structs with named fields, expands to:
//
// match None::<T> {
// Some(T { a: ref __v0, b: ref __v1 }) => {}
// _ => {}
// }
//
// For enums, expands to the following but only including struct variants:
//
// match None::<T> {
// Some(T::A { a: ref __v0 }) => {}
// Some(T::B { b: ref __v0 }) => {}
// _ => {}
// }
//
// 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
// impl.
fn pretend_fields_used(cont: &Container) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
let patterns = match cont.data {
Data::Enum(ref variants) => variants
.iter()
.filter_map(|variant| match variant.style {
Style::Struct => {
let variant_ident = &variant.ident;
let pat = struct_pattern(&variant.fields);
Some(quote!(#type_ident::#variant_ident #pat))
}
_ => None,
})
.collect::<Vec<_>>(),
Data::Struct(Style::Struct, ref fields) => {
let pat = struct_pattern(fields);
vec![quote!(#type_ident #pat)]
}
Data::Struct(_, _) => {
return quote!();
}
};
quote! {
match _serde::export::None::<#type_ident #ty_generics> {
#(
_serde::export::Some(#patterns) => {}
)*
_ => {}
}
}
}
// Expands to one of these per enum variant:
//
// match None {
// Some((__v0, __v1,)) => {
// let _ = E::V { a: __v0, b: __v1 };
// }
// _ => {}
// }
//
fn pretend_variants_used(cont: &Container) -> TokenStream {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => {
return quote!();
}
};
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
let turbofish = ty_generics.as_turbofish();
let cases = variants.iter().map(|variant| {
let variant_ident = &variant.ident;
let placeholders = &(0..variant.fields.len())
.map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
.collect::<Vec<_>>();
let pat = match variant.style {
Style::Struct => {
let members = variant.fields.iter().map(|field| &field.member);
quote!({ #(#members: #placeholders),* })
}
Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
Style::Unit => quote!(),
};
quote! {
match _serde::export::None {
_serde::export::Some((#(#placeholders,)*)) => {
let _ = #type_ident::#variant_ident #turbofish #pat;
}
_ => {}
}
}
});
quote!(#(#cases)*)
}
fn struct_pattern(fields: &[Field]) -> TokenStream {
let members = fields.iter().map(|field| &field.member);
let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#members: ref #placeholders),* })
}
+220 -74
View File
@@ -6,22 +6,20 @@
// 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 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());
@@ -33,11 +31,14 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
let impl_block = if let Some(remote) = cont.attrs.remote() { let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis; let vis = &input.vis;
let used = pretend::pretend_used(&cont);
quote! { quote! {
impl #impl_generics #ident #ty_generics #where_clause { impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer where
__S: _serde::Serializer,
{ {
#used
#body #body
} }
} }
@@ -47,7 +48,8 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
#[automatically_derived] #[automatically_derived]
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause { impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer where
__S: _serde::Serializer,
{ {
#body #body
} }
@@ -107,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);
@@ -122,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()
} }
} }
@@ -135,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(
@@ -147,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) => {
@@ -182,6 +187,26 @@ 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! {
@@ -234,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));
@@ -245,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)
@@ -275,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 })
} }
}) })
@@ -311,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 })
} }
}) })
@@ -328,7 +371,7 @@ 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;
@@ -352,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!(
@@ -394,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),* }
} }
} }
}; };
@@ -505,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);
@@ -627,20 +667,16 @@ 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();
let wrapper_generics = if let Style::Unit = variant.style { let wrapper_generics = if fields_ident.is_empty() {
params.generics.clone() params.generics.clone()
} else { } else {
bound::with_lifetime_bound(&params.generics, "'__a") bound::with_lifetime_bound(&params.generics, "'__a")
@@ -655,7 +691,8 @@ fn serialize_adjacently_tagged_variant(
impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer where
__S: _serde::Serializer,
{ {
let (#(#fields_ident,)*) = self.data; let (#(#fields_ident,)*) = self.data;
#inner #inner
@@ -733,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 {
@@ -783,6 +835,10 @@ fn serialize_struct_variant<'a>(
fields: &[Field], fields: &[Field],
name: &str, name: &str,
) -> Fragment { ) -> Fragment {
if fields.iter().any(|field| field.attrs.flatten()) {
return serialize_struct_variant_with_flatten(context, params, fields, name);
}
let struct_trait = match context { let struct_trait = match context {
StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant), StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant),
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => { StructVariant::InternallyTagged { .. } | StructVariant::Untagged => {
@@ -801,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),
} }
}) })
@@ -857,15 +913,102 @@ fn serialize_struct_variant<'a>(
} }
} }
fn serialize_struct_variant_with_flatten<'a>(
context: StructVariant<'a>,
params: &Parameters,
fields: &[Field],
name: &str,
) -> Fragment {
let struct_trait = StructTrait::SerializeMap;
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
let mut serialized_fields = fields
.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
match context {
StructVariant::ExternallyTagged {
variant_index,
variant_name,
} => {
let this = &params.this;
let fields_ty = fields.iter().map(|f| &f.ty);
let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a");
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::export::PhantomData<#this #ty_generics>,
}
impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
let (#(#members,)*) = self.data;
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
__serializer,
_serde::export::None));
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
}
_serde::Serializer::serialize_newtype_variant(
__serializer,
#name,
#variant_index,
#variant_name,
&__EnumFlatten {
data: (#(#members,)*),
phantom: _serde::export::PhantomData::<#this #ty_generics>,
})
}
}
StructVariant::InternallyTagged { tag, variant_name } => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
__serializer,
_serde::export::None));
try!(_serde::ser::SerializeMap::serialize_entry(
&mut __serde_state,
#tag,
#variant_name,
));
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
}
StructVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
__serializer,
_serde::export::None));
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
}
}
}
fn serialize_tuple_struct_visitor( fn serialize_tuple_struct_visitor(
fields: &[Field], fields: &[Field],
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());
@@ -909,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();
@@ -973,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)])
} }
@@ -982,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();
@@ -1007,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();
@@ -1034,7 +1179,8 @@ fn wrap_serialize_with(
impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error> fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer where
__S: _serde::Serializer,
{ {
#serialize_with(#(self.values.#field_access, )* __s) #serialize_with(#(self.values.#field_access, )* __s)
} }
@@ -1053,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 {
@@ -1061,7 +1207,7 @@ 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),
@@ -1087,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)
@@ -1101,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 => {
@@ -1121,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)]
+6 -3
View File
@@ -9,11 +9,14 @@ repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde_derive_internals/" documentation = "https://docs.serde.rs/serde_derive_internals/"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
readme = "README.md" readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[lib]
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" }
@@ -17,11 +17,7 @@ extern crate syn;
extern crate proc_macro2; extern crate proc_macro2;
pub mod ast; #[path = "src/mod.rs"]
pub mod attr; mod internals;
mod ctxt; pub use internals::*;
pub use ctxt::Ctxt;
mod case;
mod check;
+1
View File
@@ -0,0 +1 @@
../serde_derive/src/internals/
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.44" # remember to update html_root_url version = "1.0.59" # 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 -5
View File
@@ -1,7 +1,9 @@
use std::fmt; use std::fmt;
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, use serde::ser::{
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}; SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -24,7 +26,8 @@ pub struct Compact<T: ?Sized>(T);
/// ///
/// impl Serialize for Example { /// impl Serialize for Example {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer, /// where
/// S: Serializer,
/// { /// {
/// if serializer.is_human_readable() { /// if serializer.is_human_readable() {
/// format!("{}.{}", self.0, self.1).serialize(serializer) /// format!("{}.{}", self.0, self.1).serialize(serializer)
@@ -36,7 +39,8 @@ pub struct Compact<T: ?Sized>(T);
/// ///
/// impl<'de> Deserialize<'de> for Example { /// impl<'de> Deserialize<'de> for Example {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> /// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de>, /// where
/// D: Deserializer<'de>,
/// { /// {
/// use serde::de::Error; /// use serde::de::Error;
/// if deserializer.is_human_readable() { /// if deserializer.is_human_readable() {
@@ -476,7 +480,10 @@ use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, Varian
macro_rules! forward_deserialize_methods { macro_rules! forward_deserialize_methods {
( $wrapper : ident ( $( $name: ident ),* ) ) => { ( $wrapper : ident ( $( $name: ident ),* ) ) => {
$( $(
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> { fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
(self.0).$name($wrapper(visitor)) (self.0).$name($wrapper(visitor))
} }
)* )*
+6 -3
View File
@@ -7,8 +7,10 @@
// except according to those terms. // except according to those terms.
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer}; use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, use serde::de::{
SeqAccess, VariantAccess, Visitor}; self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
VariantAccess, Visitor,
};
use error::Error; use error::Error;
use token::Token; use token::Token;
@@ -597,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),
+20 -12
View File
@@ -68,11 +68,13 @@
//! # } //! # }
//! # //! #
//! # impl<K, V> Serialize for LinkedHashMap<K, V> //! # impl<K, V> Serialize for LinkedHashMap<K, V>
//! # where K: Serialize, //! # where
//! # V: Serialize //! # K: Serialize,
//! # V: Serialize,
//! # { //! # {
//! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> //! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//! # where S: Serializer //! # where
//! # S: Serializer,
//! # { //! # {
//! # let mut map = serializer.serialize_map(Some(self.0.len()))?; //! # let mut map = serializer.serialize_map(Some(self.0.len()))?;
//! # for &(ref k, ref v) in &self.0 { //! # for &(ref k, ref v) in &self.0 {
@@ -85,8 +87,9 @@
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>); //! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
//! # //! #
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V> //! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
//! # where K: Deserialize<'de>, //! # where
//! # V: Deserialize<'de> //! # K: Deserialize<'de>,
//! # V: Deserialize<'de>,
//! # { //! # {
//! # type Value = LinkedHashMap<K, V>; //! # type Value = LinkedHashMap<K, V>;
//! # //! #
@@ -95,7 +98,8 @@
//! # } //! # }
//! # //! #
//! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> //! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
//! # where M: MapAccess<'de> //! # where
//! # M: MapAccess<'de>,
//! # { //! # {
//! # let mut map = LinkedHashMap::new(); //! # let mut map = LinkedHashMap::new();
//! # while let Some((key, value)) = access.next_entry()? { //! # while let Some((key, value)) = access.next_entry()? {
@@ -106,11 +110,13 @@
//! # } //! # }
//! # //! #
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V> //! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
//! # where K: Deserialize<'de>, //! # where
//! # V: Deserialize<'de> //! # K: Deserialize<'de>,
//! # V: Deserialize<'de>,
//! # { //! # {
//! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> //! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//! # where D: Deserializer<'de> //! # where
//! # D: Deserializer<'de>,
//! # { //! # {
//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData)) //! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
//! # } //! # }
@@ -155,7 +161,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.44")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.59")]
#![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))]
@@ -179,8 +185,10 @@ mod assert;
mod configure; mod configure;
mod token; mod token;
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, pub use assert::{
assert_ser_tokens_error, assert_tokens}; assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
assert_tokens,
};
pub use token::Token; pub use token::Token;
pub use configure::{Compact, Configure, Readable}; pub use configure::{Compact, Configure, Readable};
@@ -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
}
@@ -10,12 +10,11 @@
extern crate serde_derive; extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked #[derive(Serialize)] //~ ERROR: proc-macro derive panicked
//~^ HELP: #[serde(flatten)] cannot be used within enums #[serde(transparent)]
enum Foo { struct S {
A { //~^^^ HELP: #[serde(transparent)] requires struct to have at most one transparent field
#[serde(flatten)] a: u8,
fields: HashMap<String, String>, b: u8,
}
} }
fn main() {} 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() {}
+413 -4
View File
@@ -15,10 +15,13 @@ 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::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, use self::serde_test::{
assert_ser_tokens_error, assert_tokens, Token}; assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
assert_tokens, Token,
};
trait MyDefault: Sized { trait MyDefault: Sized {
fn my_default() -> Self; fn my_default() -> Self;
@@ -655,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,
@@ -703,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]
@@ -741,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)]
@@ -1228,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>(
&[ &[
@@ -1240,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",
); );
} }
@@ -1791,3 +1864,339 @@ fn test_flatten_enum_newtype() {
], ],
); );
} }
#[test]
fn test_flatten_internally_tagged() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct S {
#[serde(flatten)]
x: X,
#[serde(flatten)]
y: Y,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "typeX")]
enum X {
A { a: i32 },
B { b: i32 },
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "typeY")]
enum Y {
C { c: i32 },
D { d: i32 },
}
let s = S {
x: X::B { b: 1 },
y: Y::D { d: 2 },
};
assert_tokens(
&s,
&[
Token::Map { len: None },
Token::Str("typeX"),
Token::Str("B"),
Token::Str("b"),
Token::I32(1),
Token::Str("typeY"),
Token::Str("D"),
Token::Str("d"),
Token::I32(2),
Token::MapEnd,
],
);
}
#[test]
fn test_externally_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::NewtypeVariant {
name: "Data",
variant: "A",
},
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
],
);
}
#[test]
fn test_internally_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t")]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("t"),
Token::Str("A"),
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
],
);
}
#[test]
fn test_adjacently_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
Token::StructEnd,
],
);
}
#[test]
fn test_untagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
],
);
}
#[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)]);
}
+46 -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 {
@@ -788,11 +809,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),
+94 -2
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>();
@@ -333,9 +369,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(untagged, remote = "Or")] #[serde(untagged, remote = "Or")]
enum OrDef<A, B> { enum OrDef<A, B> {
#[allow(dead_code)]
A(A), A(A),
#[allow(dead_code)]
B(B), B(B),
} }
@@ -569,6 +603,64 @@ fn test_gen() {
} }
assert::<AssocDeriveMulti<i32, NoSerdeImpl>>(); assert::<AssocDeriveMulti<i32, NoSerdeImpl>>();
#[derive(Serialize)]
#[serde(tag = "t", content = "c")]
enum EmptyAdjacentlyTagged {
#[allow(dead_code)]
Struct {},
#[allow(dead_code)]
Tuple(),
}
assert_ser::<EmptyAdjacentlyTagged>();
mod restricted {
mod inner {
#[derive(Serialize, Deserialize)]
struct Restricted {
pub(super) a: usize,
pub(in super::inner) b: usize,
}
}
}
#[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,
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
+3 -2
View File
@@ -17,8 +17,9 @@ extern crate serde_test;
mod bytes; mod bytes;
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, use self::serde_test::{
Token}; assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token,
};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::marker::PhantomData; use std::marker::PhantomData;
-2
View File
@@ -160,10 +160,8 @@ struct StructPrivDef {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")] #[serde(remote = "remote::StructPub")]
struct StructPubDef { struct StructPubDef {
#[allow(dead_code)]
a: u8, a: u8,
#[allow(dead_code)]
#[serde(with = "UnitDef")] #[serde(with = "UnitDef")]
b: remote::Unit, b: remote::Unit,
} }
+33 -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),
+8 -1
View File
@@ -55,7 +55,8 @@ else
channel build channel build
cd "$DIR/test_suite" cd "$DIR/test_suite"
channel test --features unstable channel test --features unstable
channel build --tests --features proc-macro2/nightly # Broken while syn and quote update to the new proc-macro API
#channel build --tests --features proc-macro2/nightly
if [ -z "${APPVEYOR}" ]; then if [ -z "${APPVEYOR}" ]; then
cd "$DIR/test_suite/no_std" cd "$DIR/test_suite/no_std"
channel build channel build
@@ -87,4 +88,10 @@ else
channel build --no-default-features channel build --no-default-features
cd "$DIR/serde_test" cd "$DIR/serde_test"
channel build channel build
CHANNEL=1.15.0
cd "$DIR"
cargo clean
cd "$DIR/serde_derive"
channel build
fi fi