mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-26 03:57:56 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 134f268cee | |||
| c473633676 | |||
| 6a3a82007c | |||
| 1d6ef76cfb | |||
| c8e3959435 | |||
| 796f412a1e | |||
| fa854a2108 | |||
| 3a097ff2d2 | |||
| 8463bfc1e5 | |||
| 7a72b4c624 | |||
| 670c179417 | |||
| 1b1d868837 | |||
| d9704d02bb | |||
| 1349548367 | |||
| 18b1604fc8 | |||
| 0def7da5a8 | |||
| 4bb45c8252 | |||
| bb99b31eb0 | |||
| 84397183f3 | |||
| aeae265777 | |||
| a9c5df5da1 | |||
| 96576c4de9 | |||
| 9ec68e5829 | |||
| face857d5e | |||
| 85a1cc9b4f | |||
| 630501b93d | |||
| 8bbc2995ca | |||
| 7d3872df57 | |||
| 1ed228b92b | |||
| b605cd1bb9 |
@@ -25,19 +25,17 @@ You may be looking for:
|
|||||||
<details>
|
<details>
|
||||||
<summary>
|
<summary>
|
||||||
Click to show Cargo.toml.
|
Click to show Cargo.toml.
|
||||||
<a href="https://play.rust-lang.org/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
# The core APIs, including the Serialize and Deserialize traits. Always
|
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||||
# required when using Serde.
|
# required when using Serde. The "derive" feature is only required when
|
||||||
serde = "1.0"
|
# using #[derive(Serialize, Deserialize)] to make Serde work with structs
|
||||||
|
# and enums defined in your crate.
|
||||||
# Support for #[derive(Serialize, Deserialize)]. Required if you want Serde
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
# to work for structs and enums defined in your crate.
|
|
||||||
serde_derive = "1.0"
|
|
||||||
|
|
||||||
# Each data format lives in its own crate; the sample code below uses JSON
|
# Each data format lives in its own crate; the sample code below uses JSON
|
||||||
# but you may be using a different one.
|
# but you may be using a different one.
|
||||||
@@ -48,11 +46,7 @@ serde_json = "1.0"
|
|||||||
<p></p>
|
<p></p>
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
use serde::{Serialize, Deserialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
|
|||||||
+1
-5
@@ -16,11 +16,7 @@ You may be looking for:
|
|||||||
## Serde in action
|
## Serde in action
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
use serde::{Serialize, Deserialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
|
|||||||
+2
-25
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.84" # remember to update html_root_url
|
version = "1.0.87" # 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"
|
||||||
@@ -32,30 +32,7 @@ features = ["derive", "rc"]
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|
||||||
# Re-export the derive(Serialize, Deserialize) macros. This is intended for
|
# Provide derive(Serialize, Deserialize) macros.
|
||||||
# library crates that provide optional Serde impls behind a Cargo cfg of their
|
|
||||||
# own.
|
|
||||||
#
|
|
||||||
# Mainly this is a workaround for limitations associated with
|
|
||||||
# rust-lang/cargo#1286 in which a library crate cannot use one "serde" cfg in
|
|
||||||
# Cargo to enable dependencies on both serde and serde_derive crates.
|
|
||||||
#
|
|
||||||
# The recommended way to provide optional Serde support that requires derive is
|
|
||||||
# as follows. In particular, please do not name your library's Serde feature
|
|
||||||
# anything other than "serde".
|
|
||||||
#
|
|
||||||
# [dependencies]
|
|
||||||
# serde = { version = "1.0", optional = true, features = ["derive"] }
|
|
||||||
#
|
|
||||||
# Within the library, these optional Serde derives would be written like this.
|
|
||||||
#
|
|
||||||
# #[cfg(feature = "serde")]
|
|
||||||
# #[macro_use]
|
|
||||||
# extern crate serde;
|
|
||||||
#
|
|
||||||
# #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
# struct ...
|
|
||||||
#
|
|
||||||
derive = ["serde_derive"]
|
derive = ["serde_derive"]
|
||||||
|
|
||||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ fn main() {
|
|||||||
let target = env::var("TARGET").unwrap();
|
let target = env::var("TARGET").unwrap();
|
||||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
||||||
|
|
||||||
|
// std::collections::Bound was stabilized in Rust 1.17
|
||||||
|
// but it was moved to core::ops later in Rust 1.26:
|
||||||
|
// https://doc.rust-lang.org/core/ops/enum.Bound.html
|
||||||
|
if minor >= 26 {
|
||||||
|
println!("cargo:rustc-cfg=ops_bound");
|
||||||
|
} else if minor >= 17 && cfg!(feature = "std") {
|
||||||
|
println!("cargo:rustc-cfg=collections_bound");
|
||||||
|
}
|
||||||
|
|
||||||
// CString::into_boxed_c_str stabilized in Rust 1.20:
|
// CString::into_boxed_c_str stabilized in Rust 1.20:
|
||||||
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
|
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
|
||||||
if minor >= 20 {
|
if minor >= 20 {
|
||||||
|
|||||||
@@ -2269,6 +2269,117 @@ mod range {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(any(ops_bound, collections_bound))]
|
||||||
|
impl<'de, T> Deserialize<'de> for Bound<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
enum Field {
|
||||||
|
Unbounded,
|
||||||
|
Included,
|
||||||
|
Excluded,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Field {
|
||||||
|
#[inline]
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct FieldVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for FieldVisitor {
|
||||||
|
type Value = Field;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("`Unbounded`, `Included` or `Excluded`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
0 => Ok(Field::Unbounded),
|
||||||
|
1 => Ok(Field::Included),
|
||||||
|
2 => Ok(Field::Excluded),
|
||||||
|
_ => Err(Error::invalid_value(
|
||||||
|
Unexpected::Unsigned(value as u64),
|
||||||
|
&self,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"Unbounded" => Ok(Field::Unbounded),
|
||||||
|
"Included" => Ok(Field::Included),
|
||||||
|
"Excluded" => Ok(Field::Excluded),
|
||||||
|
_ => Err(Error::unknown_variant(value, VARIANTS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
b"Unbounded" => Ok(Field::Unbounded),
|
||||||
|
b"Included" => Ok(Field::Included),
|
||||||
|
b"Excluded" => Ok(Field::Excluded),
|
||||||
|
_ => match str::from_utf8(value) {
|
||||||
|
Ok(value) => Err(Error::unknown_variant(value, VARIANTS)),
|
||||||
|
Err(_) => {
|
||||||
|
Err(Error::invalid_value(Unexpected::Bytes(value), &self))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_identifier(FieldVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BoundVisitor<T>(PhantomData<Bound<T>>);
|
||||||
|
|
||||||
|
impl<'de, T> Visitor<'de> for BoundVisitor<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
type Value = Bound<T>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("enum Bound")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: EnumAccess<'de>,
|
||||||
|
{
|
||||||
|
match try!(data.variant()) {
|
||||||
|
(Field::Unbounded, v) => v.unit_variant().map(|()| Bound::Unbounded),
|
||||||
|
(Field::Included, v) => v.newtype_variant().map(Bound::Included),
|
||||||
|
(Field::Excluded, v) => v.newtype_variant().map(Bound::Excluded),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"];
|
||||||
|
|
||||||
|
deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! nonzero_integers {
|
macro_rules! nonzero_integers {
|
||||||
( $( $T: ident, )+ ) => {
|
( $( $T: ident, )+ ) => {
|
||||||
$(
|
$(
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
//! - PathBuf
|
//! - PathBuf
|
||||||
//! - Range\<T\>
|
//! - Range\<T\>
|
||||||
//! - RangeInclusive\<T\>
|
//! - RangeInclusive\<T\>
|
||||||
|
//! - Bound\<T\>
|
||||||
//! - num::NonZero*
|
//! - num::NonZero*
|
||||||
//! - `!` *(unstable)*
|
//! - `!` *(unstable)*
|
||||||
//! - **Net types**:
|
//! - **Net types**:
|
||||||
|
|||||||
+28
-73
@@ -75,7 +75,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// 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.84")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.87")]
|
||||||
// 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
|
||||||
@@ -86,52 +86,35 @@
|
|||||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy and clippy_pedantic lints
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
feature = "cargo-clippy",
|
feature = "cargo-clippy",
|
||||||
allow(
|
allow(
|
||||||
cast_lossless,
|
// not available in our oldest supported compiler
|
||||||
const_static_lifetime,
|
const_static_lifetime,
|
||||||
doc_markdown,
|
empty_enum,
|
||||||
linkedlist,
|
|
||||||
needless_pass_by_value,
|
|
||||||
redundant_field_names,
|
redundant_field_names,
|
||||||
|
// integer and float ser/de requires these sorts of casts
|
||||||
|
cast_possible_truncation,
|
||||||
|
cast_possible_wrap,
|
||||||
|
cast_precision_loss,
|
||||||
|
cast_sign_loss,
|
||||||
|
// things are often more readable this way
|
||||||
|
cast_lossless,
|
||||||
|
module_name_repetitions,
|
||||||
|
single_match_else,
|
||||||
type_complexity,
|
type_complexity,
|
||||||
unreadable_literal,
|
use_self,
|
||||||
zero_prefixed_literal
|
zero_prefixed_literal,
|
||||||
|
// not practical
|
||||||
|
needless_pass_by_value,
|
||||||
|
similar_names,
|
||||||
|
// preference
|
||||||
|
doc_markdown,
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
// Ignored clippy_pedantic lints
|
// Rustc lints.
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
#![deny(missing_docs, unused_imports)]
|
||||||
// integer and float ser/de requires these sorts of casts
|
|
||||||
cast_possible_truncation,
|
|
||||||
cast_possible_wrap,
|
|
||||||
cast_precision_loss,
|
|
||||||
cast_sign_loss,
|
|
||||||
// simplifies some macros
|
|
||||||
invalid_upcast_comparisons,
|
|
||||||
// things are often more readable this way
|
|
||||||
decimal_literal_representation,
|
|
||||||
module_name_repetitions,
|
|
||||||
option_unwrap_used,
|
|
||||||
result_unwrap_used,
|
|
||||||
shadow_reuse,
|
|
||||||
single_match_else,
|
|
||||||
use_self,
|
|
||||||
// not practical
|
|
||||||
indexing_slicing,
|
|
||||||
many_single_char_names,
|
|
||||||
missing_docs_in_private_items,
|
|
||||||
similar_names,
|
|
||||||
// alternative is not stable
|
|
||||||
empty_enum,
|
|
||||||
use_debug,
|
|
||||||
))]
|
|
||||||
// Blacklisted Rust lints.
|
|
||||||
//
|
|
||||||
// Compiler bug involving unused_imports:
|
|
||||||
// https://github.com/rust-lang/rust/issues/51661
|
|
||||||
#![deny(missing_docs, /*unused_imports*/)]
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -224,6 +207,12 @@ mod lib {
|
|||||||
|
|
||||||
#[cfg(range_inclusive)]
|
#[cfg(range_inclusive)]
|
||||||
pub use self::core::ops::RangeInclusive;
|
pub use self::core::ops::RangeInclusive;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", collections_bound))]
|
||||||
|
pub use std::collections::Bound;
|
||||||
|
|
||||||
|
#[cfg(ops_bound)]
|
||||||
|
pub use self::core::ops::Bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -252,40 +241,6 @@ pub mod private;
|
|||||||
|
|
||||||
// Re-export #[derive(Serialize, Deserialize)].
|
// Re-export #[derive(Serialize, Deserialize)].
|
||||||
//
|
//
|
||||||
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
|
|
||||||
// Without this re-export, crates that put Serde derives behind a cfg_attr would
|
|
||||||
// need to use some silly feature name that depends on both serde and
|
|
||||||
// serde_derive.
|
|
||||||
//
|
|
||||||
// [features]
|
|
||||||
// serde-impls = ["serde", "serde_derive"]
|
|
||||||
//
|
|
||||||
// [dependencies]
|
|
||||||
// serde = { version = "1.0", optional = true }
|
|
||||||
// serde_derive = { version = "1.0", optional = true }
|
|
||||||
//
|
|
||||||
// # Used like this:
|
|
||||||
// # #[cfg(feature = "serde-impls")]
|
|
||||||
// # #[macro_use]
|
|
||||||
// # extern crate serde_derive;
|
|
||||||
// #
|
|
||||||
// # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
|
|
||||||
// # struct S { /* ... */ }
|
|
||||||
//
|
|
||||||
// The re-exported derives allow crates to use "serde" as the name of their
|
|
||||||
// Serde feature which is more intuitive.
|
|
||||||
//
|
|
||||||
// [dependencies]
|
|
||||||
// serde = { version = "1.0", optional = true, features = ["derive"] }
|
|
||||||
//
|
|
||||||
// # Used like this:
|
|
||||||
// # #[cfg(feature = "serde")]
|
|
||||||
// # #[macro_use]
|
|
||||||
// # extern crate serde;
|
|
||||||
// #
|
|
||||||
// # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
// # struct S { /* ... */ }
|
|
||||||
//
|
|
||||||
// The reason re-exporting is not enabled by default is that disabling it would
|
// The reason re-exporting is not enabled by default is that disabling it would
|
||||||
// be annoying for crates that provide handwritten impls or data formats. They
|
// be annoying for crates that provide handwritten impls or data formats. They
|
||||||
// would need to disable default features and then explicitly re-enable std.
|
// would need to disable default features and then explicitly re-enable std.
|
||||||
|
|||||||
@@ -256,6 +256,29 @@ where
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(any(ops_bound, collections_bound))]
|
||||||
|
impl<T> Serialize for Bound<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"),
|
||||||
|
Bound::Included(ref value) => {
|
||||||
|
serializer.serialize_newtype_variant("Bound", 1, "Included", value)
|
||||||
|
}
|
||||||
|
Bound::Excluded(ref value) => {
|
||||||
|
serializer.serialize_newtype_variant("Bound", 2, "Excluded", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl Serialize for () {
|
impl Serialize for () {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
//! - PathBuf
|
//! - PathBuf
|
||||||
//! - Range\<T\>
|
//! - Range\<T\>
|
||||||
//! - RangeInclusive\<T\>
|
//! - RangeInclusive\<T\>
|
||||||
|
//! - Bound\<T\>
|
||||||
//! - num::NonZero*
|
//! - num::NonZero*
|
||||||
//! - `!` *(unstable)*
|
//! - `!` *(unstable)*
|
||||||
//! - **Net types**:
|
//! - **Net types**:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.84" # remember to update html_root_url
|
version = "1.0.87" # 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)]"
|
||||||
|
|||||||
+73
-77
@@ -1140,25 +1140,21 @@ fn deserialize_enum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_externally_tagged_enum(
|
fn prepare_enum_variant_enum(
|
||||||
params: &Parameters,
|
|
||||||
variants: &[Variant],
|
variants: &[Variant],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> (TokenStream, Stmts) {
|
||||||
let this = ¶ms.this;
|
|
||||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
|
||||||
split_with_de_lifetime(params);
|
|
||||||
let delife = params.borrowed.de_lifetime();
|
|
||||||
|
|
||||||
let type_name = cattrs.name().deserialize_name();
|
|
||||||
|
|
||||||
let expecting = format!("enum {}", params.type_name());
|
|
||||||
|
|
||||||
let variant_names_idents: Vec<_> = variants
|
let variant_names_idents: Vec<_> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||||
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
|
.map(|(i, variant)| {
|
||||||
|
(
|
||||||
|
variant.attrs.name().deserialize_name(),
|
||||||
|
field_i(i),
|
||||||
|
variant.attrs.aliases(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let other_idx = variants
|
let other_idx = variants
|
||||||
@@ -1166,7 +1162,7 @@ fn deserialize_externally_tagged_enum(
|
|||||||
.position(|ref variant| variant.attrs.other());
|
.position(|ref variant| variant.attrs.other());
|
||||||
|
|
||||||
let variants_stmt = {
|
let variants_stmt = {
|
||||||
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
|
let variant_names = variant_names_idents.iter().map(|&(ref name, _, _)| name);
|
||||||
quote! {
|
quote! {
|
||||||
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
|
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
|
||||||
}
|
}
|
||||||
@@ -1179,6 +1175,24 @@ fn deserialize_externally_tagged_enum(
|
|||||||
other_idx,
|
other_idx,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
(variants_stmt, variant_visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_externally_tagged_enum(
|
||||||
|
params: &Parameters,
|
||||||
|
variants: &[Variant],
|
||||||
|
cattrs: &attr::Container,
|
||||||
|
) -> Fragment {
|
||||||
|
let this = ¶ms.this;
|
||||||
|
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||||
|
split_with_de_lifetime(params);
|
||||||
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
|
||||||
|
let type_name = cattrs.name().deserialize_name();
|
||||||
|
let expecting = format!("enum {}", params.type_name());
|
||||||
|
|
||||||
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
||||||
|
|
||||||
// Match arms to extract a variant from a string
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1261,30 +1275,7 @@ fn deserialize_internally_tagged_enum(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
tag: &str,
|
tag: &str,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let variant_names_idents: Vec<_> = variants
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
|
||||||
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let other_idx = variants
|
|
||||||
.iter()
|
|
||||||
.position(|ref variant| variant.attrs.other());
|
|
||||||
|
|
||||||
let variants_stmt = {
|
|
||||||
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
|
|
||||||
quote! {
|
|
||||||
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
|
||||||
&variant_names_idents,
|
|
||||||
cattrs,
|
|
||||||
true,
|
|
||||||
other_idx,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Match arms to extract a variant from a string
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
@@ -1335,30 +1326,7 @@ fn deserialize_adjacently_tagged_enum(
|
|||||||
split_with_de_lifetime(params);
|
split_with_de_lifetime(params);
|
||||||
let delife = params.borrowed.de_lifetime();
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
|
||||||
let variant_names_idents: Vec<_> = variants
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
|
||||||
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let other_idx = variants
|
|
||||||
.iter()
|
|
||||||
.position(|ref variant| variant.attrs.other());
|
|
||||||
|
|
||||||
let variants_stmt = {
|
|
||||||
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
|
|
||||||
quote! {
|
|
||||||
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
|
||||||
&variant_names_idents,
|
|
||||||
cattrs,
|
|
||||||
true,
|
|
||||||
other_idx,
|
|
||||||
));
|
|
||||||
|
|
||||||
let variant_arms: &Vec<_> = &variants
|
let variant_arms: &Vec<_> = &variants
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1870,13 +1838,13 @@ fn deserialize_untagged_newtype_variant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_generated_identifier(
|
fn deserialize_generated_identifier(
|
||||||
fields: &[(String, Ident)],
|
fields: &[(String, Ident, Vec<String>)],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
is_variant: bool,
|
is_variant: bool,
|
||||||
other_idx: Option<usize>,
|
other_idx: Option<usize>,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let this = quote!(__Field);
|
let this = quote!(__Field);
|
||||||
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
|
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident, _)| ident).collect();
|
||||||
|
|
||||||
let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() {
|
let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() {
|
||||||
let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),);
|
let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),);
|
||||||
@@ -1977,11 +1945,12 @@ fn deserialize_custom_identifier(
|
|||||||
(
|
(
|
||||||
variant.attrs.name().deserialize_name(),
|
variant.attrs.name().deserialize_name(),
|
||||||
variant.ident.clone(),
|
variant.ident.clone(),
|
||||||
|
variant.attrs.aliases(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let names = names_idents.iter().map(|&(ref name, _)| name);
|
let names = names_idents.iter().map(|&(ref name, _, _)| name);
|
||||||
|
|
||||||
let names_const = if fallthrough.is_some() {
|
let names_const = if fallthrough.is_some() {
|
||||||
None
|
None
|
||||||
@@ -2032,24 +2001,33 @@ fn deserialize_custom_identifier(
|
|||||||
|
|
||||||
fn deserialize_identifier(
|
fn deserialize_identifier(
|
||||||
this: &TokenStream,
|
this: &TokenStream,
|
||||||
fields: &[(String, Ident)],
|
fields: &[(String, Ident, Vec<String>)],
|
||||||
is_variant: bool,
|
is_variant: bool,
|
||||||
fallthrough: Option<TokenStream>,
|
fallthrough: Option<TokenStream>,
|
||||||
collect_other_fields: bool,
|
collect_other_fields: bool,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let field_strs = fields.iter().map(|&(ref name, _)| name);
|
let mut flat_fields = Vec::new();
|
||||||
let field_borrowed_strs = fields.iter().map(|&(ref name, _)| name);
|
for &(_, ref ident, ref aliases) in fields {
|
||||||
let field_bytes = fields
|
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let field_strs = flat_fields.iter().map(|&(ref name, _)| name);
|
||||||
|
let field_borrowed_strs = flat_fields.iter().map(|&(ref name, _)| name);
|
||||||
|
let field_bytes = flat_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
||||||
let field_borrowed_bytes = fields
|
let field_borrowed_bytes = flat_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
||||||
|
|
||||||
let constructors: &Vec<_> = &fields
|
let constructors: &Vec<_> = &flat_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(_, ref ident)| quote!(#this::#ident))
|
.map(|&(_, ref ident)| quote!(#this::#ident))
|
||||||
.collect();
|
.collect();
|
||||||
|
let main_constructors: &Vec<_> = &fields
|
||||||
|
.iter()
|
||||||
|
.map(|&(_, ref ident, _)| quote!(#this::#ident))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let expecting = if is_variant {
|
let expecting = if is_variant {
|
||||||
"variant identifier"
|
"variant identifier"
|
||||||
@@ -2237,7 +2215,7 @@ fn deserialize_identifier(
|
|||||||
{
|
{
|
||||||
match __value {
|
match __value {
|
||||||
#(
|
#(
|
||||||
#variant_indices => _serde::export::Ok(#constructors),
|
#variant_indices => _serde::export::Ok(#main_constructors),
|
||||||
)*
|
)*
|
||||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||||
_serde::de::Unexpected::Unsigned(__value),
|
_serde::de::Unexpected::Unsigned(__value),
|
||||||
@@ -2300,11 +2278,17 @@ fn deserialize_struct_as_struct_visitor(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||||
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
|
.map(|(i, field)| {
|
||||||
|
(
|
||||||
|
field.attrs.name().deserialize_name(),
|
||||||
|
field_i(i),
|
||||||
|
field.attrs.aliases(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let fields_stmt = {
|
let fields_stmt = {
|
||||||
let field_names = field_names_idents.iter().map(|&(ref name, _)| name);
|
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name);
|
||||||
quote_block! {
|
quote_block! {
|
||||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||||
}
|
}
|
||||||
@@ -2327,7 +2311,13 @@ fn deserialize_struct_as_map_visitor(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||||
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
|
.map(|(i, field)| {
|
||||||
|
(
|
||||||
|
field.attrs.name().deserialize_name(),
|
||||||
|
field_i(i),
|
||||||
|
field.attrs.aliases(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
|
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
|
||||||
@@ -2558,11 +2548,17 @@ fn deserialize_struct_as_struct_in_place_visitor(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||||
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
|
.map(|(i, field)| {
|
||||||
|
(
|
||||||
|
field.attrs.name().deserialize_name(),
|
||||||
|
field_i(i),
|
||||||
|
field.attrs.aliases(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let fields_stmt = {
|
let fields_stmt = {
|
||||||
let field_names = field_names_idents.iter().map(|&(ref name, _)| name);
|
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name);
|
||||||
quote_block! {
|
quote_block! {
|
||||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use syn::NestedMeta::{Literal, Meta};
|
|||||||
|
|
||||||
pub use internals::case::RenameRule;
|
pub use internals::case::RenameRule;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Attr<'c, T> {
|
struct Attr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
@@ -90,9 +89,54 @@ impl<'c> BoolAttr<'c> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VecAttr<'c, T> {
|
||||||
|
cx: &'c Ctxt,
|
||||||
|
name: &'static str,
|
||||||
|
first_dup_tokens: TokenStream,
|
||||||
|
values: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'c, T> VecAttr<'c, T> {
|
||||||
|
fn none(cx: &'c Ctxt, name: &'static str) -> Self {
|
||||||
|
VecAttr {
|
||||||
|
cx: cx,
|
||||||
|
name: name,
|
||||||
|
first_dup_tokens: TokenStream::new(),
|
||||||
|
values: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert<A: ToTokens>(&mut self, obj: A, value: T) {
|
||||||
|
if self.values.len() == 1 {
|
||||||
|
self.first_dup_tokens = obj.into_token_stream();
|
||||||
|
}
|
||||||
|
self.values.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn at_most_one(mut self) -> Result<Option<T>, ()> {
|
||||||
|
if self.values.len() > 1 {
|
||||||
|
let dup_token = self.first_dup_tokens;
|
||||||
|
self.cx.error_spanned_by(
|
||||||
|
dup_token,
|
||||||
|
format!("duplicate serde attribute `{}`", self.name),
|
||||||
|
);
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(self.values.pop())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self) -> Vec<T> {
|
||||||
|
self.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Name {
|
pub struct Name {
|
||||||
serialize: String,
|
serialize: String,
|
||||||
|
serialize_renamed: bool,
|
||||||
deserialize: String,
|
deserialize: String,
|
||||||
|
deserialize_renamed: bool,
|
||||||
|
deserialize_aliases: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@@ -104,6 +148,36 @@ fn unraw(ident: &Ident) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Name {
|
impl Name {
|
||||||
|
fn from_attrs(
|
||||||
|
source_name: String,
|
||||||
|
ser_name: Attr<String>,
|
||||||
|
de_name: Attr<String>,
|
||||||
|
de_aliases: Option<VecAttr<String>>,
|
||||||
|
) -> Name {
|
||||||
|
let deserialize_aliases = match de_aliases {
|
||||||
|
Some(de_aliases) => {
|
||||||
|
let mut alias_list = BTreeSet::new();
|
||||||
|
for alias_name in de_aliases.get() {
|
||||||
|
alias_list.insert(alias_name);
|
||||||
|
}
|
||||||
|
alias_list.into_iter().collect()
|
||||||
|
}
|
||||||
|
None => Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ser_name = ser_name.get();
|
||||||
|
let ser_renamed = ser_name.is_some();
|
||||||
|
let de_name = de_name.get();
|
||||||
|
let de_renamed = de_name.is_some();
|
||||||
|
Name {
|
||||||
|
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
|
||||||
|
serialize_renamed: ser_renamed,
|
||||||
|
deserialize: de_name.unwrap_or(source_name),
|
||||||
|
deserialize_renamed: de_renamed,
|
||||||
|
deserialize_aliases: deserialize_aliases,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the container name for the container when serializing.
|
/// Return the container name for the container when serializing.
|
||||||
pub fn serialize_name(&self) -> String {
|
pub fn serialize_name(&self) -> String {
|
||||||
self.serialize.clone()
|
self.serialize.clone()
|
||||||
@@ -113,6 +187,15 @@ impl Name {
|
|||||||
pub fn deserialize_name(&self) -> String {
|
pub fn deserialize_name(&self) -> String {
|
||||||
self.deserialize.clone()
|
self.deserialize.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_aliases(&self) -> Vec<String> {
|
||||||
|
let mut aliases = self.deserialize_aliases.clone();
|
||||||
|
let main_name = self.deserialize_name();
|
||||||
|
if !aliases.contains(&main_name) {
|
||||||
|
aliases.push(main_name);
|
||||||
|
}
|
||||||
|
aliases
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenameAllRules {
|
pub struct RenameAllRules {
|
||||||
@@ -514,10 +597,7 @@ impl Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Container {
|
Container {
|
||||||
name: Name {
|
name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None),
|
||||||
serialize: ser_name.get().unwrap_or_else(|| unraw(&item.ident)),
|
|
||||||
deserialize: de_name.get().unwrap_or_else(|| unraw(&item.ident)),
|
|
||||||
},
|
|
||||||
transparent: transparent.get(),
|
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),
|
||||||
@@ -762,8 +842,6 @@ fn decide_identifier(
|
|||||||
/// Represents variant attribute information
|
/// Represents variant attribute information
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
name: Name,
|
name: Name,
|
||||||
ser_renamed: bool,
|
|
||||||
de_renamed: bool,
|
|
||||||
rename_all_rules: RenameAllRules,
|
rename_all_rules: RenameAllRules,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
@@ -779,6 +857,7 @@ impl Variant {
|
|||||||
pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self {
|
pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> 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 de_aliases = VecAttr::none(cx, "rename");
|
||||||
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_ser_rule = Attr::none(cx, "rename_all");
|
let mut rename_all_ser_rule = Attr::none(cx, "rename_all");
|
||||||
@@ -797,15 +876,26 @@ impl Variant {
|
|||||||
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, &m.ident, &m.lit) {
|
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
|
||||||
ser_name.set(&m.ident, s.value());
|
ser_name.set(&m.ident, s.value());
|
||||||
de_name.set(&m.ident, s.value());
|
de_name.set_if_none(s.value());
|
||||||
|
de_aliases.insert(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
||||||
Meta(List(ref m)) if m.ident == "rename" => {
|
Meta(List(ref m)) if m.ident == "rename" => {
|
||||||
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) {
|
||||||
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
||||||
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
|
for de_value in de {
|
||||||
|
de_name.set_if_none(de_value.value());
|
||||||
|
de_aliases.insert(&m.ident, de_value.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(alias = "foo")]`
|
||||||
|
Meta(NameValue(ref m)) if m.ident == "alias" => {
|
||||||
|
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
|
||||||
|
de_aliases.insert(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,17 +1053,8 @@ impl Variant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ser_name = ser_name.get();
|
|
||||||
let ser_renamed = ser_name.is_some();
|
|
||||||
let de_name = de_name.get();
|
|
||||||
let de_renamed = de_name.is_some();
|
|
||||||
Variant {
|
Variant {
|
||||||
name: Name {
|
name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)),
|
||||||
serialize: ser_name.unwrap_or_else(|| unraw(&variant.ident)),
|
|
||||||
deserialize: de_name.unwrap_or_else(|| unraw(&variant.ident)),
|
|
||||||
},
|
|
||||||
ser_renamed: ser_renamed,
|
|
||||||
de_renamed: de_renamed,
|
|
||||||
rename_all_rules: RenameAllRules {
|
rename_all_rules: RenameAllRules {
|
||||||
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
||||||
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
||||||
@@ -993,11 +1074,15 @@ impl Variant {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn aliases(&self) -> Vec<String> {
|
||||||
|
self.name.deserialize_aliases()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
||||||
if !self.ser_renamed {
|
if !self.name.serialize_renamed {
|
||||||
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
|
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
|
||||||
}
|
}
|
||||||
if !self.de_renamed {
|
if !self.name.deserialize_renamed {
|
||||||
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
|
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1038,8 +1123,6 @@ impl Variant {
|
|||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
name: Name,
|
name: Name,
|
||||||
ser_renamed: bool,
|
|
||||||
de_renamed: bool,
|
|
||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing_if: Option<syn::ExprPath>,
|
skip_serializing_if: Option<syn::ExprPath>,
|
||||||
@@ -1084,6 +1167,7 @@ impl Field {
|
|||||||
) -> Self {
|
) -> 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 de_aliases = VecAttr::none(cx, "rename");
|
||||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||||
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
||||||
let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if");
|
let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if");
|
||||||
@@ -1117,15 +1201,26 @@ impl Field {
|
|||||||
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, &m.ident, &m.lit) {
|
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
|
||||||
ser_name.set(&m.ident, s.value());
|
ser_name.set(&m.ident, s.value());
|
||||||
de_name.set(&m.ident, s.value());
|
de_name.set_if_none(s.value());
|
||||||
|
de_aliases.insert(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
||||||
Meta(List(ref m)) if m.ident == "rename" => {
|
Meta(List(ref m)) if m.ident == "rename" => {
|
||||||
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) {
|
||||||
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
||||||
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
|
for de_value in de {
|
||||||
|
de_name.set_if_none(de_value.value());
|
||||||
|
de_aliases.insert(&m.ident, de_value.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(alias = "foo")]`
|
||||||
|
Meta(NameValue(ref m)) if m.ident == "alias" => {
|
||||||
|
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
|
||||||
|
de_aliases.insert(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1332,17 +1427,8 @@ impl Field {
|
|||||||
collect_lifetimes(&field.ty, &mut borrowed_lifetimes);
|
collect_lifetimes(&field.ty, &mut borrowed_lifetimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ser_name = ser_name.get();
|
|
||||||
let ser_renamed = ser_name.is_some();
|
|
||||||
let de_name = de_name.get();
|
|
||||||
let de_renamed = de_name.is_some();
|
|
||||||
Field {
|
Field {
|
||||||
name: Name {
|
name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
|
||||||
serialize: ser_name.unwrap_or_else(|| ident.clone()),
|
|
||||||
deserialize: de_name.unwrap_or(ident),
|
|
||||||
},
|
|
||||||
ser_renamed: ser_renamed,
|
|
||||||
de_renamed: de_renamed,
|
|
||||||
skip_serializing: skip_serializing.get(),
|
skip_serializing: skip_serializing.get(),
|
||||||
skip_deserializing: skip_deserializing.get(),
|
skip_deserializing: skip_deserializing.get(),
|
||||||
skip_serializing_if: skip_serializing_if.get(),
|
skip_serializing_if: skip_serializing_if.get(),
|
||||||
@@ -1362,11 +1448,15 @@ impl Field {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn aliases(&self) -> Vec<String> {
|
||||||
|
self.name.deserialize_aliases()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
||||||
if !self.ser_renamed {
|
if !self.name.serialize_renamed {
|
||||||
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
|
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
|
||||||
}
|
}
|
||||||
if !self.de_renamed {
|
if !self.name.deserialize_renamed {
|
||||||
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
|
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1426,31 +1516,31 @@ impl Field {
|
|||||||
|
|
||||||
type SerAndDe<T> = (Option<T>, Option<T>);
|
type SerAndDe<T> = (Option<T>, Option<T>);
|
||||||
|
|
||||||
fn get_ser_and_de<'a, T, F>(
|
fn get_ser_and_de<'a, 'b, T, F>(
|
||||||
cx: &Ctxt,
|
cx: &'b Ctxt,
|
||||||
attr_name: &'static str,
|
attr_name: &'static str,
|
||||||
metas: &'a Punctuated<syn::NestedMeta, Token![,]>,
|
metas: &'a Punctuated<syn::NestedMeta, Token![,]>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<SerAndDe<T>, ()>
|
) -> Result<(VecAttr<'b, T>, VecAttr<'b, T>), ()>
|
||||||
where
|
where
|
||||||
T: 'a,
|
T: 'a,
|
||||||
F: Fn(&Ctxt, &Ident, &Ident, &'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 = VecAttr::none(cx, attr_name);
|
||||||
let mut de_meta = Attr::none(cx, attr_name);
|
let mut de_meta = VecAttr::none(cx, attr_name);
|
||||||
let attr_name = Ident::new(attr_name, Span::call_site());
|
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, &meta.lit) {
|
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
||||||
ser_meta.set(&meta.ident, v);
|
ser_meta.insert(&meta.ident, 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, &meta.lit) {
|
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
||||||
de_meta.set(&meta.ident, v);
|
de_meta.insert(&meta.ident, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1468,21 +1558,31 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((ser_meta.get(), de_meta.get()))
|
Ok((ser_meta, de_meta))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_renames<'a>(
|
fn get_renames<'a>(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
items: &'a Punctuated<syn::NestedMeta, Token![,]>,
|
items: &'a Punctuated<syn::NestedMeta, Token![,]>,
|
||||||
) -> Result<SerAndDe<&'a syn::LitStr>, ()> {
|
) -> Result<SerAndDe<&'a syn::LitStr>, ()> {
|
||||||
get_ser_and_de(cx, "rename", items, get_lit_str)
|
let (ser, de) = try!(get_ser_and_de(cx, "rename", items, get_lit_str));
|
||||||
|
Ok((try!(ser.at_most_one()), try!(de.at_most_one())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_multiple_renames<'a>(
|
||||||
|
cx: &Ctxt,
|
||||||
|
items: &'a Punctuated<syn::NestedMeta, Token![,]>,
|
||||||
|
) -> Result<(Option<&'a syn::LitStr>, Vec<&'a syn::LitStr>), ()> {
|
||||||
|
let (ser, de) = try!(get_ser_and_de(cx, "rename", items, get_lit_str));
|
||||||
|
Ok((try!(ser.at_most_one()), de.get()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_where_predicates(
|
fn get_where_predicates(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
items: &Punctuated<syn::NestedMeta, Token![,]>,
|
items: &Punctuated<syn::NestedMeta, Token![,]>,
|
||||||
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
|
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
|
||||||
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
|
let (ser, de) = try!(get_ser_and_de(cx, "bound", items, parse_lit_into_where));
|
||||||
|
Ok((try!(ser.at_most_one()), try!(de.at_most_one())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> {
|
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> {
|
||||||
|
|||||||
@@ -295,12 +295,18 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
|||||||
let check_de = !field.attrs.skip_deserializing();
|
let check_de = !field.attrs.skip_deserializing();
|
||||||
let name = field.attrs.name();
|
let name = field.attrs.name();
|
||||||
let ser_name = name.serialize_name();
|
let ser_name = name.serialize_name();
|
||||||
let de_name = name.deserialize_name();
|
|
||||||
|
|
||||||
if check_ser && ser_name == tag || check_de && de_name == tag {
|
if check_ser && ser_name == tag {
|
||||||
diagnose_conflict();
|
diagnose_conflict();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for de_name in field.attrs.aliases() {
|
||||||
|
if check_de && de_name == tag {
|
||||||
|
diagnose_conflict();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Unit | Style::Newtype | Style::Tuple => {}
|
Style::Unit | Style::Newtype | Style::Tuple => {}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [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.84")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.87")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
|
|||||||
+28
-19
@@ -289,37 +289,38 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream {
|
||||||
|
match *cattrs.tag() {
|
||||||
|
attr::TagType::Internal { ref tag } => {
|
||||||
|
let type_name = cattrs.name().serialize_name();
|
||||||
|
let func = struct_trait.serialize_field(Span::call_site());
|
||||||
|
quote! {
|
||||||
|
try!(#func(&mut __serde_state, #tag, #type_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => quote! {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_struct_as_struct(
|
fn serialize_struct_as_struct(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let mut serialize_fields =
|
let serialize_fields =
|
||||||
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct);
|
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct);
|
||||||
|
|
||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
|
|
||||||
let additional_field_count: usize = match *cattrs.tag() {
|
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct);
|
||||||
attr::TagType::Internal { ref tag } => {
|
let tag_field_exists = !tag_field.is_empty();
|
||||||
let func = StructTrait::SerializeStruct.serialize_field(Span::call_site());
|
|
||||||
serialize_fields.insert(
|
|
||||||
0,
|
|
||||||
quote! {
|
|
||||||
try!(#func(&mut __serde_state, #tag, #type_name));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
1
|
|
||||||
}
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some() || additional_field_count > 0);
|
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||||
|
|
||||||
let len = serialized_fields
|
let len = serialized_fields
|
||||||
.map(|field| match field.attrs.skip_serializing_if() {
|
.map(|field| match field.attrs.skip_serializing_if() {
|
||||||
@@ -330,12 +331,13 @@ fn serialize_struct_as_struct(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold(
|
.fold(
|
||||||
quote!(#additional_field_count),
|
quote!(#tag_field_exists as usize),
|
||||||
|sum, expr| quote!(#sum + #expr),
|
|sum, expr| quote!(#sum + #expr),
|
||||||
);
|
);
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
|
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
|
||||||
|
#tag_field
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStruct::end(__serde_state)
|
_serde::ser::SerializeStruct::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -349,12 +351,15 @@ fn serialize_struct_as_map(
|
|||||||
let serialize_fields =
|
let serialize_fields =
|
||||||
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
|
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
|
||||||
|
|
||||||
|
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap);
|
||||||
|
let tag_field_exists = !tag_field.is_empty();
|
||||||
|
|
||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||||
|
|
||||||
let len = if cattrs.has_flatten() {
|
let len = if cattrs.has_flatten() {
|
||||||
quote!(_serde::export::None)
|
quote!(_serde::export::None)
|
||||||
@@ -367,12 +372,16 @@ fn serialize_struct_as_map(
|
|||||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
.fold(
|
||||||
|
quote!(#tag_field_exists as usize),
|
||||||
|
|sum, expr| quote!(#sum + #expr),
|
||||||
|
);
|
||||||
quote!(_serde::export::Some(#len))
|
quote!(_serde::export::Some(#len))
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
||||||
|
#tag_field
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_test"
|
name = "serde_test"
|
||||||
version = "1.0.84" # remember to update html_root_url
|
version = "1.0.87" # 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"
|
||||||
|
|||||||
@@ -144,7 +144,7 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.84")]
|
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.87")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use compiletest_rs as compiletest;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ui() {
|
fn ui() {
|
||||||
let config = compiletest::Config {
|
compiletest::run_tests(&compiletest::Config {
|
||||||
mode: compiletest::common::Mode::Ui,
|
mode: compiletest::common::Mode::Ui,
|
||||||
src_base: std::path::PathBuf::from("tests/ui"),
|
src_base: std::path::PathBuf::from("tests/ui"),
|
||||||
target_rustcflags: Some(String::from(
|
target_rustcflags: Some(String::from(
|
||||||
@@ -16,7 +16,5 @@ fn ui() {
|
|||||||
",
|
",
|
||||||
)),
|
)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
});
|
||||||
|
|
||||||
compiletest::run_tests(&config);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,6 +516,16 @@ struct RenameStructSerializeDeserialize {
|
|||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct AliasStruct {
|
||||||
|
a1: i32,
|
||||||
|
#[serde(alias = "a3")]
|
||||||
|
a2: i32,
|
||||||
|
#[serde(alias = "a5", rename = "a6")]
|
||||||
|
a4: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rename_struct() {
|
fn test_rename_struct() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
@@ -562,6 +572,67 @@ fn test_rename_struct() {
|
|||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AliasStruct {
|
||||||
|
a1: 1,
|
||||||
|
a2: 2,
|
||||||
|
a4: 3,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AliasStruct",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::Str("a2"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::Str("a5"),
|
||||||
|
Token::I32(3),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AliasStruct {
|
||||||
|
a1: 1,
|
||||||
|
a2: 2,
|
||||||
|
a4: 3,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AliasStruct",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::Str("a6"),
|
||||||
|
Token::I32(3),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unknown_field_rename_struct() {
|
||||||
|
assert_de_tokens_error::<AliasStruct>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AliasStruct",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::Str("a4"),
|
||||||
|
Token::I32(3),
|
||||||
|
],
|
||||||
|
"unknown field `a4`, expected one of `a1`, `a2`, `a6`",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -592,6 +663,19 @@ enum RenameEnumSerializeDeserialize<A> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
enum AliasEnum {
|
||||||
|
#[serde(rename = "sailor_moon", alias = "usagi_tsukino")]
|
||||||
|
SailorMoon {
|
||||||
|
a: i8,
|
||||||
|
#[serde(alias = "c")]
|
||||||
|
b: i8,
|
||||||
|
#[serde(alias = "e", rename = "f")]
|
||||||
|
d: i8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rename_enum() {
|
fn test_rename_enum() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
@@ -678,6 +762,71 @@ fn test_rename_enum() {
|
|||||||
Token::StructVariantEnd,
|
Token::StructVariantEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AliasEnum::SailorMoon { a: 0, b: 1, d: 2 },
|
||||||
|
&[
|
||||||
|
Token::StructVariant {
|
||||||
|
name: "AliasEnum",
|
||||||
|
variant: "sailor_moon",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(0),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I8(1),
|
||||||
|
Token::Str("e"),
|
||||||
|
Token::I8(2),
|
||||||
|
Token::StructVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AliasEnum::SailorMoon { a: 0, b: 1, d: 2 },
|
||||||
|
&[
|
||||||
|
Token::StructVariant {
|
||||||
|
name: "AliasEnum",
|
||||||
|
variant: "usagi_tsukino",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(0),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::I8(1),
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::I8(2),
|
||||||
|
Token::StructVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unknown_field_rename_enum() {
|
||||||
|
assert_de_tokens_error::<AliasEnum>(
|
||||||
|
&[Token::StructVariant {
|
||||||
|
name: "AliasEnum",
|
||||||
|
variant: "SailorMoon",
|
||||||
|
len: 3,
|
||||||
|
}],
|
||||||
|
"unknown variant `SailorMoon`, expected `sailor_moon`",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AliasEnum>(
|
||||||
|
&[
|
||||||
|
Token::StructVariant {
|
||||||
|
name: "AliasEnum",
|
||||||
|
variant: "usagi_tsukino",
|
||||||
|
len: 3,
|
||||||
|
},
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(0),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::I8(1),
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::I8(2),
|
||||||
|
],
|
||||||
|
"unknown field `d`, expected one of `a`, `b`, `f`",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::default::Default;
|
|||||||
use std::ffi::{CStr, CString, OsString};
|
use std::ffi::{CStr, CString, OsString};
|
||||||
use std::net;
|
use std::net;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
|
use std::ops::Bound;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::{Rc, Weak as RcWeak};
|
use std::rc::{Rc, Weak as RcWeak};
|
||||||
use std::sync::{Arc, Weak as ArcWeak};
|
use std::sync::{Arc, Weak as ArcWeak};
|
||||||
@@ -836,6 +837,23 @@ declare_tests! {
|
|||||||
Token::SeqEnd,
|
Token::SeqEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
test_bound {
|
||||||
|
Bound::Unbounded::<()> => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Unbounded"),
|
||||||
|
Token::Unit,
|
||||||
|
],
|
||||||
|
Bound::Included(0) => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Included"),
|
||||||
|
Token::U8(0),
|
||||||
|
],
|
||||||
|
Bound::Excluded(0) => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Excluded"),
|
||||||
|
Token::U8(0),
|
||||||
|
],
|
||||||
|
}
|
||||||
test_path {
|
test_path {
|
||||||
Path::new("/usr/local/lib") => &[
|
Path::new("/usr/local/lib") => &[
|
||||||
Token::BorrowedStr("/usr/local/lib"),
|
Token::BorrowedStr("/usr/local/lib"),
|
||||||
|
|||||||
@@ -1424,6 +1424,48 @@ fn test_internally_tagged_braced_struct_with_zero_fields() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_internally_tagged_struct_with_flattened_field() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "tag_struct")]
|
||||||
|
pub struct Struct {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub flat: Enum,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "tag_enum", content = "content")]
|
||||||
|
pub enum Enum {
|
||||||
|
A(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Struct { flat: Enum::A(0) },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("tag_struct"),
|
||||||
|
Token::Str("Struct"),
|
||||||
|
Token::Str("tag_enum"),
|
||||||
|
Token::Str("A"),
|
||||||
|
Token::Str("content"),
|
||||||
|
Token::U64(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Struct { flat: Enum::A(0) },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("tag_enum"),
|
||||||
|
Token::Str("A"),
|
||||||
|
Token::Str("content"),
|
||||||
|
Token::U64(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enum_in_untagged_enum() {
|
fn test_enum_in_untagged_enum() {
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::ffi::CString;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net;
|
use std::net;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
|
use std::ops::Bound;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::{Rc, Weak as RcWeak};
|
use std::rc::{Rc, Weak as RcWeak};
|
||||||
use std::sync::{Arc, Weak as ArcWeak};
|
use std::sync::{Arc, Weak as ArcWeak};
|
||||||
@@ -375,6 +376,23 @@ declare_tests! {
|
|||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
test_bound {
|
||||||
|
Bound::Unbounded::<()> => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Unbounded"),
|
||||||
|
Token::Unit,
|
||||||
|
],
|
||||||
|
Bound::Included(0u8) => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Included"),
|
||||||
|
Token::U8(0),
|
||||||
|
],
|
||||||
|
Bound::Excluded(0u8) => &[
|
||||||
|
Token::Enum { name: "Bound" },
|
||||||
|
Token::Str("Excluded"),
|
||||||
|
Token::U8(0),
|
||||||
|
],
|
||||||
|
}
|
||||||
test_path {
|
test_path {
|
||||||
Path::new("/usr/local/lib") => &[
|
Path::new("/usr/local/lib") => &[
|
||||||
Token::Str("/usr/local/lib"),
|
Token::Str("/usr/local/lib"),
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(tag = "conflict")]
|
||||||
|
enum E {
|
||||||
|
A {
|
||||||
|
#[serde(alias = "conflict")]
|
||||||
|
x: (),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
error: variant field name `conflict` conflicts with internal tag
|
||||||
|
--> $DIR/internal-tag-alias.rs:4:1
|
||||||
|
|
|
||||||
|
4 | / #[serde(tag = "conflict")]
|
||||||
|
5 | | enum E {
|
||||||
|
6 | | A {
|
||||||
|
7 | | #[serde(alias = "conflict")]
|
||||||
|
8 | | x: (),
|
||||||
|
9 | | },
|
||||||
|
10 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
use serde_derive::Serialize;
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct S {
|
|
||||||
#[serde(rename = "x")]
|
|
||||||
#[serde(rename(deserialize = "y"))]
|
|
||||||
x: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
error: duplicate serde attribute `rename`
|
|
||||||
--> $DIR/rename-rename-de.rs:6:13
|
|
||||||
|
|
|
||||||
6 | #[serde(rename(deserialize = "y"))]
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user