mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-27 21:37:55 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88d5fe6bfd | |||
| 9a2c352025 | |||
| 61c90cb8cb | |||
| 66e8b0a0cd | |||
| 9e7a3437d9 | |||
| 7ac8d4f9ae | |||
| 501bae42f5 | |||
| 7a0397451e | |||
| 16787318d1 | |||
| f4ae0888c8 | |||
| 213071fe5c | |||
| cfd26c6fda | |||
| 23fa83941e | |||
| 88f5b9511d | |||
| d537f1e1f0 | |||
| f6ac232580 | |||
| aad7a7987f | |||
| b24ad76880 | |||
| 5796f1a0f5 | |||
| 6437167930 | |||
| f98daaa250 | |||
| b8a40551a2 | |||
| 40db31691a | |||
| ab68132b1f | |||
| e70bbd9dde | |||
| d5e5c520ac | |||
| 1b9a096fa7 | |||
| 39e05ffad2 | |||
| 78fab25c5c | |||
| 2a557a1e36 | |||
| ab0848f780 | |||
| 2b1303f59c | |||
| 7f9ba155cb | |||
| a4e0c2f055 | |||
| 3bbf70575b |
@@ -20,9 +20,30 @@ You may be looking for:
|
|||||||
|
|
||||||
## Serde in action
|
## Serde in action
|
||||||
|
|
||||||
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">
|
<details>
|
||||||
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
<summary>
|
||||||
</a>
|
Click to show Cargo.toml.
|
||||||
|
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||||
|
# required when using Serde.
|
||||||
|
serde = "1.0"
|
||||||
|
|
||||||
|
# Support for #[derive(Serialize, Deserialize)]. Required if you want Serde
|
||||||
|
# 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
|
||||||
|
# but you may be using a different one.
|
||||||
|
serde_json = "1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<p></p>
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.17" # remember to update html_root_url
|
version = "1.0.19" # 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"
|
||||||
|
|||||||
+3
-1
@@ -79,7 +79,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.17")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.19")]
|
||||||
|
|
||||||
// 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)]
|
||||||
@@ -95,8 +95,10 @@
|
|||||||
// Whitelisted clippy lints
|
// Whitelisted clippy lints
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||||
cast_lossless,
|
cast_lossless,
|
||||||
|
const_static_lifetime,
|
||||||
doc_markdown,
|
doc_markdown,
|
||||||
linkedlist,
|
linkedlist,
|
||||||
|
needless_pass_by_value,
|
||||||
type_complexity,
|
type_complexity,
|
||||||
unreadable_literal,
|
unreadable_literal,
|
||||||
zero_prefixed_literal,
|
zero_prefixed_literal,
|
||||||
|
|||||||
+30
-2
@@ -1114,10 +1114,38 @@ mod content {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_unit_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
visitor: V
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.content {
|
||||||
|
// As a special case, allow deserializing untagged newtype
|
||||||
|
// variant containing unit struct.
|
||||||
|
//
|
||||||
|
// #[derive(Deserialize)]
|
||||||
|
// struct Info;
|
||||||
|
//
|
||||||
|
// #[derive(Deserialize)]
|
||||||
|
// #[serde(tag = "topic")]
|
||||||
|
// enum Message {
|
||||||
|
// Info(Info),
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We want {"topic":"Info"} to deserialize even though
|
||||||
|
// ordinarily unit structs do not deserialize from empty map.
|
||||||
|
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
|
||||||
|
_ => self.deserialize_any(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
forward_to_deserialize_any! {
|
||||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||||
byte_buf unit unit_struct seq tuple tuple_struct map struct
|
byte_buf unit seq tuple tuple_struct map struct identifier
|
||||||
identifier ignored_any
|
ignored_any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ enum Unsupported {
|
|||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
Unit,
|
Unit,
|
||||||
UnitStruct,
|
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
@@ -79,7 +78,6 @@ impl Display for Unsupported {
|
|||||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||||
Unsupported::Optional => formatter.write_str("an optional"),
|
Unsupported::Optional => formatter.write_str("an optional"),
|
||||||
Unsupported::Unit => formatter.write_str("unit"),
|
Unsupported::Unit => formatter.write_str("unit"),
|
||||||
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
|
|
||||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||||
@@ -199,7 +197,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::UnitStruct))
|
let mut map = try!(self.delegate.serialize_map(Some(1)));
|
||||||
|
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
|
map.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.17" # remember to update html_root_url
|
version = "1.0.19" # 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)]"
|
||||||
@@ -20,7 +20,7 @@ proc-macro = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "0.3.8"
|
quote = "0.3.8"
|
||||||
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
|
serde_derive_internals = { version = "=0.17.0", default-features = false, path = "../serde_derive_internals" }
|
||||||
syn = { version = "0.11", features = ["visit"] }
|
syn = { version = "0.11", features = ["visit"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -116,6 +116,14 @@ where
|
|||||||
}
|
}
|
||||||
visit::walk_path(self, path);
|
visit::walk_path(self, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type parameter should not be considered used by a macro path.
|
||||||
|
//
|
||||||
|
// struct TypeMacro<T> {
|
||||||
|
// mac: T!(),
|
||||||
|
// marker: PhantomData<T>,
|
||||||
|
// }
|
||||||
|
fn visit_mac(&mut self, _mac: &syn::Mac) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_ty_params: HashSet<_> = generics
|
let all_ty_params: HashSet<_> = generics
|
||||||
|
|||||||
@@ -203,7 +203,9 @@ impl BorrowedLifetimes {
|
|||||||
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
||||||
let mut lifetimes = BTreeSet::new();
|
let mut lifetimes = BTreeSet::new();
|
||||||
for field in cont.body.all_fields() {
|
for field in cont.body.all_fields() {
|
||||||
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
if !field.attrs.skip_deserializing() {
|
||||||
|
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if lifetimes.iter().any(|b| b.ident == "'static") {
|
if lifetimes.iter().any(|b| b.ident == "'static") {
|
||||||
BorrowedLifetimes::Static
|
BorrowedLifetimes::Static
|
||||||
|
|||||||
@@ -22,7 +22,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.17")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.19")]
|
||||||
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive_internals"
|
name = "serde_derive_internals"
|
||||||
version = "0.16.0" # remember to update html_root_url
|
version = "0.17.0" # 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 = "AST representation used by Serde derive macros. Unstable."
|
description = "AST representation used by Serde derive macros. Unstable."
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl<'a> Container<'a> {
|
|||||||
let mut body = match item.body {
|
let mut body = match item.body {
|
||||||
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
|
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
|
||||||
syn::Body::Struct(ref variant_data) => {
|
syn::Body::Struct(ref variant_data) => {
|
||||||
let (style, fields) = struct_from_ast(cx, variant_data);
|
let (style, fields) = struct_from_ast(cx, variant_data, None);
|
||||||
Body::Struct(style, fields)
|
Body::Struct(style, fields)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -103,10 +103,11 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
|
|||||||
.iter()
|
.iter()
|
||||||
.map(
|
.map(
|
||||||
|variant| {
|
|variant| {
|
||||||
let (style, fields) = struct_from_ast(cx, &variant.data);
|
let attrs = attr::Variant::from_ast(cx, variant);
|
||||||
|
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
|
||||||
Variant {
|
Variant {
|
||||||
ident: variant.ident.clone(),
|
ident: variant.ident.clone(),
|
||||||
attrs: attr::Variant::from_ast(cx, variant),
|
attrs: attrs,
|
||||||
style: style,
|
style: style,
|
||||||
fields: fields,
|
fields: fields,
|
||||||
}
|
}
|
||||||
@@ -115,18 +116,18 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) {
|
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
|
||||||
match *data {
|
match *data {
|
||||||
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)),
|
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
|
||||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
||||||
(Style::Newtype, fields_from_ast(cx, fields))
|
(Style::Newtype, fields_from_ast(cx, fields, attrs))
|
||||||
}
|
}
|
||||||
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)),
|
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
|
||||||
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -134,7 +135,7 @@ fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|
|||||||
|(i, field)| {
|
|(i, field)| {
|
||||||
Field {
|
Field {
|
||||||
ident: field.ident.clone(),
|
ident: field.ident.clone(),
|
||||||
attrs: attr::Field::from_ast(cx, i, field),
|
attrs: attr::Field::from_ast(cx, i, field, attrs),
|
||||||
ty: &field.ty,
|
ty: &field.ty,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -512,6 +512,7 @@ pub struct Variant {
|
|||||||
other: bool,
|
other: bool,
|
||||||
serialize_with: Option<syn::Path>,
|
serialize_with: Option<syn::Path>,
|
||||||
deserialize_with: Option<syn::Path>,
|
deserialize_with: Option<syn::Path>,
|
||||||
|
borrow: Option<syn::MetaItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variant {
|
impl Variant {
|
||||||
@@ -524,6 +525,7 @@ impl Variant {
|
|||||||
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");
|
||||||
|
let mut borrow = Attr::none(cx, "borrow");
|
||||||
|
|
||||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
@@ -599,6 +601,18 @@ impl Variant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
|
||||||
|
MetaItem(ref mi) if mi.name() == "borrow" => {
|
||||||
|
match variant.data {
|
||||||
|
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
||||||
|
borrow.set(mi.clone());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cx.error("#[serde(borrow)] may only be used on newtype variants");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MetaItem(ref meta_item) => {
|
MetaItem(ref meta_item) => {
|
||||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||||
}
|
}
|
||||||
@@ -627,6 +641,7 @@ impl Variant {
|
|||||||
other: other.get(),
|
other: other.get(),
|
||||||
serialize_with: serialize_with.get(),
|
serialize_with: serialize_with.get(),
|
||||||
deserialize_with: deserialize_with.get(),
|
deserialize_with: deserialize_with.get(),
|
||||||
|
borrow: borrow.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +714,7 @@ pub enum Default {
|
|||||||
|
|
||||||
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(cx: &Ctxt, index: usize, field: &syn::Field) -> Self {
|
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field, attrs: Option<&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 skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||||
@@ -718,7 +733,13 @@ impl Field {
|
|||||||
None => index.to_string(),
|
None => index.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
let variant_borrow = attrs
|
||||||
|
.map(|variant| &variant.borrow)
|
||||||
|
.unwrap_or(&None)
|
||||||
|
.as_ref()
|
||||||
|
.map(|borrow| vec![MetaItem(borrow.clone())]);
|
||||||
|
|
||||||
|
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items).chain(variant_borrow) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
match meta_item {
|
match meta_item {
|
||||||
// Parse `#[serde(rename = "foo")]`
|
// Parse `#[serde(rename = "foo")]`
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
|
||||||
|
#[allow(unused_imports)]
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use self::RenameRule::*;
|
use self::RenameRule::*;
|
||||||
|
|||||||
@@ -6,7 +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.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.17.0")]
|
||||||
|
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_test"
|
name = "serde_test"
|
||||||
version = "1.0.17" # remember to update html_root_url
|
version = "1.0.19" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
description = "Token De/Serializer for testing De/Serialize implementations"
|
||||||
@@ -12,10 +12,10 @@ readme = "README.md"
|
|||||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", path = "../serde" }
|
serde = { version = "1.0.16", path = "../serde" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = { version = "1.0", path = "../serde", features = ["rc"] }
|
serde = { version = "1.0.16", path = "../serde", features = ["rc"] }
|
||||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
|
|||||||
@@ -6,7 +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 serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use de::Deserializer;
|
use de::Deserializer;
|
||||||
use ser::Serializer;
|
use ser::Serializer;
|
||||||
@@ -47,20 +47,8 @@ pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
|||||||
where
|
where
|
||||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||||
{
|
{
|
||||||
assert_tokens_readable(value, tokens, None);
|
assert_ser_tokens(value, tokens);
|
||||||
}
|
assert_de_tokens(value, tokens);
|
||||||
|
|
||||||
// Not public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
|
||||||
///
|
|
||||||
/// See: `assert_tokens`
|
|
||||||
pub fn assert_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
|
||||||
where
|
|
||||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
|
||||||
{
|
|
||||||
assert_ser_tokens_readable(value, tokens, human_readable);
|
|
||||||
assert_de_tokens_readable(value, tokens, human_readable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that `value` serializes to the given `tokens`.
|
/// Asserts that `value` serializes to the given `tokens`.
|
||||||
@@ -96,19 +84,7 @@ pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
|||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
assert_ser_tokens_readable(value, tokens, None)
|
let mut ser = Serializer::new(tokens);
|
||||||
}
|
|
||||||
|
|
||||||
// Not public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
/// Asserts that `value` serializes to the given `tokens`.
|
|
||||||
///
|
|
||||||
/// See: `assert_ser_tokens`
|
|
||||||
pub fn assert_ser_tokens_readable<T>(value: &T, tokens: &[Token], human_readable: Option<bool>)
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
let mut ser = Serializer::readable(tokens, human_readable);
|
|
||||||
match value.serialize(&mut ser) {
|
match value.serialize(&mut ser) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => panic!("value failed to serialize: {}", err),
|
Err(err) => panic!("value failed to serialize: {}", err),
|
||||||
@@ -207,16 +183,7 @@ pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
|||||||
where
|
where
|
||||||
T: Deserialize<'de> + PartialEq + Debug,
|
T: Deserialize<'de> + PartialEq + Debug,
|
||||||
{
|
{
|
||||||
assert_de_tokens_readable(value, tokens, None)
|
let mut de = Deserializer::new(tokens);
|
||||||
}
|
|
||||||
|
|
||||||
// Not public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn assert_de_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
|
||||||
where
|
|
||||||
T: Deserialize<'de> + PartialEq + Debug,
|
|
||||||
{
|
|
||||||
let mut de = Deserializer::readable(tokens, human_readable);
|
|
||||||
match T::deserialize(&mut de) {
|
match T::deserialize(&mut de) {
|
||||||
Ok(v) => assert_eq!(v, *value),
|
Ok(v) => assert_eq!(v, *value),
|
||||||
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
||||||
|
|||||||
@@ -0,0 +1,661 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||||
|
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Readable<T: ?Sized>(T);
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Compact<T: ?Sized>(T);
|
||||||
|
|
||||||
|
/// Trait to determine whether a value is represented in human-readable or
|
||||||
|
/// compact form.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// extern crate serde;
|
||||||
|
/// extern crate serde_test;
|
||||||
|
///
|
||||||
|
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
/// use serde_test::{Configure, Token, assert_tokens};
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, PartialEq)]
|
||||||
|
/// struct Example(u8, u8);
|
||||||
|
///
|
||||||
|
/// impl Serialize for Example {
|
||||||
|
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
/// where S: Serializer,
|
||||||
|
/// {
|
||||||
|
/// if serializer.is_human_readable() {
|
||||||
|
/// format!("{}.{}", self.0, self.1).serialize(serializer)
|
||||||
|
/// } else {
|
||||||
|
/// (self.0, self.1).serialize(serializer)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl<'de> Deserialize<'de> for Example {
|
||||||
|
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
/// where D: Deserializer<'de>,
|
||||||
|
/// {
|
||||||
|
/// use serde::de::Error;
|
||||||
|
/// if deserializer.is_human_readable() {
|
||||||
|
/// let s = String::deserialize(deserializer)?;
|
||||||
|
/// let parts: Vec<_> = s.split('.').collect();
|
||||||
|
/// Ok(Example(
|
||||||
|
/// parts[0].parse().map_err(D::Error::custom)?,
|
||||||
|
/// parts[1].parse().map_err(D::Error::custom)?,
|
||||||
|
/// ))
|
||||||
|
/// } else {
|
||||||
|
/// let (x, y) = Deserialize::deserialize(deserializer)?;
|
||||||
|
/// Ok(Example(x, y))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// assert_tokens(
|
||||||
|
/// &Example(1, 0).compact(),
|
||||||
|
/// &[
|
||||||
|
/// Token::Tuple { len: 2 },
|
||||||
|
/// Token::U8(1),
|
||||||
|
/// Token::U8(0),
|
||||||
|
/// Token::TupleEnd,
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// assert_tokens(
|
||||||
|
/// &Example(1, 0).readable(),
|
||||||
|
/// &[
|
||||||
|
/// Token::Str("1.0"),
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait Configure {
|
||||||
|
/// Marks `self` as using `is_human_readable == true`
|
||||||
|
fn readable(self) -> Readable<Self> where Self: Sized {
|
||||||
|
Readable(self)
|
||||||
|
}
|
||||||
|
/// Marks `self` as using `is_human_readable == false`
|
||||||
|
fn compact(self) -> Compact<Self> where Self: Sized {
|
||||||
|
Compact(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Configure for T {}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Serialize for Readable<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.0.serialize(Readable(serializer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: ?Sized> Serialize for Compact<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.0.serialize(Compact(serializer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de, T> Deserialize<'de> for Readable<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
T::deserialize(Readable(deserializer)).map(Readable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de, T> Deserialize<'de> for Compact<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
T::deserialize(Compact(deserializer)).map(Compact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, T> DeserializeSeed<'de> for Readable<T>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
type Value = T::Value;
|
||||||
|
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
self.0.deserialize(Readable(deserializer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de, T> DeserializeSeed<'de> for Compact<T>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
type Value = T::Value;
|
||||||
|
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
self.0.deserialize(Compact(deserializer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! forward_method {
|
||||||
|
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
|
||||||
|
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
|
||||||
|
(self.0).$name( $($arg),* )
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! forward_serialize_methods {
|
||||||
|
( $( $name: ident $arg_type: ty ),* ) => {
|
||||||
|
$(
|
||||||
|
forward_method!($name(self, v : $arg_type) -> Result<Self::Ok, Self::Error>);
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_serializer {
|
||||||
|
($wrapper: ident, $is_human_readable : expr) => {
|
||||||
|
impl<S> Serializer for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
|
||||||
|
type SerializeSeq = $wrapper<S::SerializeSeq>;
|
||||||
|
type SerializeTuple = $wrapper<S::SerializeTuple>;
|
||||||
|
type SerializeTupleStruct = $wrapper<S::SerializeTupleStruct>;
|
||||||
|
type SerializeTupleVariant = $wrapper<S::SerializeTupleVariant>;
|
||||||
|
type SerializeMap = $wrapper<S::SerializeMap>;
|
||||||
|
type SerializeStruct = $wrapper<S::SerializeStruct>;
|
||||||
|
type SerializeStructVariant = $wrapper<S::SerializeStructVariant>;
|
||||||
|
|
||||||
|
fn is_human_readable(&self) -> bool {
|
||||||
|
$is_human_readable
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
forward_serialize_methods!{
|
||||||
|
serialize_bool bool,
|
||||||
|
serialize_i8 i8,
|
||||||
|
serialize_i16 i16,
|
||||||
|
serialize_i32 i32,
|
||||||
|
serialize_i64 i64,
|
||||||
|
serialize_u8 u8,
|
||||||
|
serialize_u16 u16,
|
||||||
|
serialize_u32 u32,
|
||||||
|
serialize_u64 u64,
|
||||||
|
serialize_f32 f32,
|
||||||
|
serialize_f64 f64,
|
||||||
|
serialize_char char,
|
||||||
|
serialize_str &str,
|
||||||
|
serialize_bytes &[u8],
|
||||||
|
serialize_unit_struct &'static str
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.serialize_unit()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.serialize_unit_variant(name, variant_index, variant)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_struct<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_newtype_struct(name, &$wrapper(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0
|
||||||
|
.serialize_newtype_variant(name, variant_index, variant, &$wrapper(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_none(self) -> Result<S::Ok, Self::Error> {
|
||||||
|
self.0.serialize_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<S::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_some(&$wrapper(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
|
self.0.serialize_seq(len).map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||||
|
self.0.serialize_tuple(len).map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||||
|
self.0.serialize_tuple_struct(name, len).map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
|
self.0
|
||||||
|
.serialize_tuple_variant(name, variant_index, variant, len)
|
||||||
|
.map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
|
self.0.serialize_map(len).map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
|
self.0.serialize_struct(name, len).map($wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
|
self.0
|
||||||
|
.serialize_struct_variant(name, variant_index, variant, len)
|
||||||
|
.map($wrapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeSeq for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeSeq,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_element(&$wrapper(value))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeTuple for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeTuple,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_element(&$wrapper(value))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeTupleStruct for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeTupleStruct,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_field(&$wrapper(value))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeTupleVariant for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeTupleVariant,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_field(&$wrapper(value))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeMap for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeMap,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_key(&$wrapper(key))
|
||||||
|
}
|
||||||
|
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_value(&$wrapper(value))
|
||||||
|
}
|
||||||
|
fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
K: Serialize,
|
||||||
|
V: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_entry(key, &$wrapper(value))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeStruct for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeStruct,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, name: &'static str, field: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_field(name, &$wrapper(field))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> SerializeStructVariant for $wrapper<S>
|
||||||
|
where
|
||||||
|
S: SerializeStructVariant,
|
||||||
|
{
|
||||||
|
type Ok = S::Ok;
|
||||||
|
type Error = S::Error;
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, name: &'static str, field: &T) -> Result<(), S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_field(name, &$wrapper(field))
|
||||||
|
}
|
||||||
|
fn end(self) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_serializer!(Readable, true);
|
||||||
|
impl_serializer!(Compact, false);
|
||||||
|
|
||||||
|
|
||||||
|
use serde::de::{Visitor, EnumAccess, VariantAccess, MapAccess, DeserializeSeed, SeqAccess, Error};
|
||||||
|
|
||||||
|
macro_rules! forward_deserialize_methods {
|
||||||
|
( $wrapper : ident ( $( $name: ident ),* ) ) => {
|
||||||
|
$(
|
||||||
|
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
(self.0).$name($wrapper(visitor))
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! impl_deserializer {
|
||||||
|
($wrapper : ident, $is_human_readable : expr) => {
|
||||||
|
impl <'de, D> Deserializer<'de> for $wrapper<D> where D: Deserializer<'de> {
|
||||||
|
type Error = D::Error;
|
||||||
|
|
||||||
|
forward_deserialize_methods! {
|
||||||
|
$wrapper (
|
||||||
|
deserialize_any,
|
||||||
|
deserialize_bool,
|
||||||
|
deserialize_u8,
|
||||||
|
deserialize_u16,
|
||||||
|
deserialize_u32,
|
||||||
|
deserialize_u64,
|
||||||
|
deserialize_i8,
|
||||||
|
deserialize_i16,
|
||||||
|
deserialize_i32,
|
||||||
|
deserialize_i64,
|
||||||
|
deserialize_f32,
|
||||||
|
deserialize_f64,
|
||||||
|
deserialize_char,
|
||||||
|
deserialize_str,
|
||||||
|
deserialize_string,
|
||||||
|
deserialize_bytes,
|
||||||
|
deserialize_byte_buf,
|
||||||
|
deserialize_option,
|
||||||
|
deserialize_unit,
|
||||||
|
deserialize_seq,
|
||||||
|
deserialize_map,
|
||||||
|
deserialize_identifier,
|
||||||
|
deserialize_ignored_any
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_unit_struct(name, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_newtype_struct(name, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_tuple(len, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn deserialize_tuple_struct<V>(self, name: &'static str, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_tuple_struct(name, len, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn deserialize_struct<V>(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_struct(name, fields, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn deserialize_enum<V>(self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.deserialize_enum(name, variants, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_human_readable(&self) -> bool {
|
||||||
|
$is_human_readable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, D> Visitor<'de> for $wrapper<D> where D: Visitor<'de> {
|
||||||
|
type Value = D::Value;
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.0.expecting(formatter)
|
||||||
|
}
|
||||||
|
fn visit_bool<E>(self, v: bool) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_bool(v)
|
||||||
|
}
|
||||||
|
fn visit_i8<E>(self, v: i8) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_i8(v)
|
||||||
|
}
|
||||||
|
fn visit_i16<E>(self, v: i16) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_i16(v)
|
||||||
|
}
|
||||||
|
fn visit_i32<E>(self, v: i32) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_i32(v)
|
||||||
|
}
|
||||||
|
fn visit_i64<E>(self, v: i64) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_i64(v)
|
||||||
|
}
|
||||||
|
fn visit_u8<E>(self, v: u8) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_u8(v)
|
||||||
|
}
|
||||||
|
fn visit_u16<E>(self, v: u16) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_u16(v)
|
||||||
|
}
|
||||||
|
fn visit_u32<E>(self, v: u32) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_u32(v)
|
||||||
|
}
|
||||||
|
fn visit_u64<E>(self, v: u64) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_u64(v)
|
||||||
|
}
|
||||||
|
fn visit_f32<E>(self, v: f32) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_f32(v)
|
||||||
|
}
|
||||||
|
fn visit_f64<E>(self, v: f64) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_f64(v)
|
||||||
|
}
|
||||||
|
fn visit_char<E>(self, v: char) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_char(v)
|
||||||
|
}
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_str(v)
|
||||||
|
}
|
||||||
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_borrowed_str(v)
|
||||||
|
}
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_string(v)
|
||||||
|
}
|
||||||
|
fn visit_bytes<E>(self, v: &[u8]) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_bytes(v)
|
||||||
|
}
|
||||||
|
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_borrowed_bytes(v)
|
||||||
|
}
|
||||||
|
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_byte_buf(v)
|
||||||
|
}
|
||||||
|
fn visit_none<E>(self) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_none()
|
||||||
|
}
|
||||||
|
fn visit_some<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error> where D2: Deserializer<'de> {
|
||||||
|
self.0.visit_some($wrapper(deserializer))
|
||||||
|
}
|
||||||
|
fn visit_unit<E>(self) -> Result<D::Value, E> where E: Error {
|
||||||
|
self.0.visit_unit()
|
||||||
|
}
|
||||||
|
fn visit_newtype_struct<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error> where D2: Deserializer<'de> {
|
||||||
|
self.0.visit_newtype_struct($wrapper(deserializer))
|
||||||
|
}
|
||||||
|
fn visit_seq<V>(self, seq: V) -> Result<D::Value, V::Error> where V: SeqAccess<'de> {
|
||||||
|
self.0.visit_seq($wrapper(seq))
|
||||||
|
}
|
||||||
|
fn visit_map<V>(self, map: V) -> Result<D::Value, V::Error> where V: MapAccess<'de> {
|
||||||
|
self.0.visit_map($wrapper(map))
|
||||||
|
}
|
||||||
|
fn visit_enum<V>(self, data: V) -> Result<D::Value, V::Error> where V: EnumAccess<'de> {
|
||||||
|
self.0.visit_enum($wrapper(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, D> SeqAccess<'de> for $wrapper<D> where D: SeqAccess<'de> {
|
||||||
|
type Error = D::Error;
|
||||||
|
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, D::Error> where T: DeserializeSeed<'de> {
|
||||||
|
self.0.next_element_seed($wrapper(seed))
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> Option<usize> {
|
||||||
|
self.0.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, D> MapAccess<'de> for $wrapper<D> where D: MapAccess<'de> {
|
||||||
|
type Error = D::Error;
|
||||||
|
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, D::Error> where K: DeserializeSeed<'de> {
|
||||||
|
self.0.next_key_seed($wrapper(seed))
|
||||||
|
}
|
||||||
|
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, D::Error> where V: DeserializeSeed<'de> {
|
||||||
|
self.0.next_value_seed($wrapper(seed))
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> Option<usize> {
|
||||||
|
self.0.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, D> EnumAccess<'de> for $wrapper<D> where D: EnumAccess<'de> {
|
||||||
|
type Error = D::Error;
|
||||||
|
type Variant = $wrapper<D::Variant>;
|
||||||
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de> {
|
||||||
|
self.0.variant_seed($wrapper(seed)).map(|(value, variant)| (value, $wrapper(variant)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, D> VariantAccess<'de> for $wrapper<D> where D: VariantAccess<'de> {
|
||||||
|
type Error = D::Error;
|
||||||
|
fn unit_variant(self) -> Result<(), D::Error> {
|
||||||
|
self.0.unit_variant()
|
||||||
|
}
|
||||||
|
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, D::Error> where T: DeserializeSeed<'de> {
|
||||||
|
self.0.newtype_variant_seed($wrapper(seed))
|
||||||
|
}
|
||||||
|
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.tuple_variant(len, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||||
|
self.0.struct_variant(fields, $wrapper(visitor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_deserializer!(Readable, true);
|
||||||
|
impl_deserializer!(Compact, false);
|
||||||
+40
-53
@@ -16,7 +16,6 @@ use token::Token;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Deserializer<'de> {
|
pub struct Deserializer<'de> {
|
||||||
tokens: &'de [Token],
|
tokens: &'de [Token],
|
||||||
is_human_readable: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! assert_next_token {
|
macro_rules! assert_next_token {
|
||||||
@@ -49,13 +48,7 @@ macro_rules! end_of_tokens {
|
|||||||
|
|
||||||
impl<'de> Deserializer<'de> {
|
impl<'de> Deserializer<'de> {
|
||||||
pub fn new(tokens: &'de [Token]) -> Self {
|
pub fn new(tokens: &'de [Token]) -> Self {
|
||||||
Deserializer::readable(tokens, None)
|
Deserializer { tokens: tokens }
|
||||||
}
|
|
||||||
|
|
||||||
// Not public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn readable(tokens: &'de [Token], is_human_readable: Option<bool>) -> Self {
|
|
||||||
Deserializer { tokens: tokens, is_human_readable: is_human_readable }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_token_opt(&self) -> Option<Token> {
|
fn peek_token_opt(&self) -> Option<Token> {
|
||||||
@@ -107,7 +100,7 @@ impl<'de> Deserializer<'de> {
|
|||||||
DeserializerSeqVisitor {
|
DeserializerSeqVisitor {
|
||||||
de: self,
|
de: self,
|
||||||
len: len,
|
len: len,
|
||||||
end: end.clone(),
|
end: end,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -129,7 +122,7 @@ impl<'de> Deserializer<'de> {
|
|||||||
DeserializerMapVisitor {
|
DeserializerMapVisitor {
|
||||||
de: self,
|
de: self,
|
||||||
len: len,
|
len: len,
|
||||||
end: end.clone(),
|
end: end,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -172,15 +165,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()),
|
Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()),
|
||||||
Token::None => visitor.visit_none(),
|
Token::None => visitor.visit_none(),
|
||||||
Token::Some => visitor.visit_some(self),
|
Token::Some => visitor.visit_some(self),
|
||||||
Token::Unit => visitor.visit_unit(),
|
Token::Unit | Token::UnitStruct { .. } => visitor.visit_unit(),
|
||||||
Token::UnitStruct { name: _ } => visitor.visit_unit(),
|
Token::NewtypeStruct { .. } => visitor.visit_newtype_struct(self),
|
||||||
Token::NewtypeStruct { name: _ } => visitor.visit_newtype_struct(self),
|
|
||||||
Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, visitor),
|
Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, visitor),
|
||||||
Token::Tuple { len } => self.visit_seq(Some(len), Token::TupleEnd, visitor),
|
Token::Tuple { len } => self.visit_seq(Some(len), Token::TupleEnd, visitor),
|
||||||
Token::TupleStruct { name: _, len } => self.visit_seq(Some(len), Token::TupleStructEnd, visitor),
|
Token::TupleStruct { len, .. } => self.visit_seq(Some(len), Token::TupleStructEnd, visitor),
|
||||||
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
|
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
|
||||||
Token::Struct { name: _, len } => self.visit_map(Some(len), Token::StructEnd, visitor),
|
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
|
||||||
Token::Enum { name: _ } => {
|
Token::Enum { .. } => {
|
||||||
let variant = self.next_token();
|
let variant = self.next_token();
|
||||||
let next = self.peek_token();
|
let next = self.peek_token();
|
||||||
match (variant, next) {
|
match (variant, next) {
|
||||||
@@ -202,14 +194,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::UnitVariant { name: _, variant } => visitor.visit_str(variant),
|
Token::UnitVariant { variant, .. } => visitor.visit_str(variant),
|
||||||
Token::NewtypeVariant { name: _, variant } => {
|
Token::NewtypeVariant { variant, .. } => {
|
||||||
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Any),)
|
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Any),)
|
||||||
}
|
}
|
||||||
Token::TupleVariant { name: _, variant, len: _ } => {
|
Token::TupleVariant { variant, .. } => {
|
||||||
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Seq),)
|
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Seq),)
|
||||||
}
|
}
|
||||||
Token::StructVariant { name: _, variant, len: _ } => {
|
Token::StructVariant { variant, .. } => {
|
||||||
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Map),)
|
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Map),)
|
||||||
}
|
}
|
||||||
Token::SeqEnd | Token::TupleEnd | Token::TupleStructEnd | Token::MapEnd |
|
Token::SeqEnd | Token::TupleEnd | Token::TupleStructEnd | Token::MapEnd |
|
||||||
@@ -252,10 +244,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
|
|
||||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
||||||
}
|
}
|
||||||
Token::UnitVariant { name: n, variant: _ } |
|
Token::UnitVariant { name: n, .. } |
|
||||||
Token::NewtypeVariant { name: n, variant: _ } |
|
Token::NewtypeVariant { name: n, .. } |
|
||||||
Token::TupleVariant { name: n, variant: _, len: _ } |
|
Token::TupleVariant { name: n, .. } |
|
||||||
Token::StructVariant { name: n, variant: _, len: _ } if name == n => {
|
Token::StructVariant { name: n, .. } if name == n => {
|
||||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -269,7 +261,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.peek_token() {
|
match self.peek_token() {
|
||||||
Token::UnitStruct { name: _ } => {
|
Token::UnitStruct { .. } => {
|
||||||
assert_next_token!(self, Token::UnitStruct { name: name });
|
assert_next_token!(self, Token::UnitStruct { name: name });
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
@@ -282,7 +274,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.peek_token() {
|
match self.peek_token() {
|
||||||
Token::NewtypeStruct { name: _ } => {
|
Token::NewtypeStruct { .. } => {
|
||||||
assert_next_token!(self, Token::NewtypeStruct { name: name });
|
assert_next_token!(self, Token::NewtypeStruct { name: name });
|
||||||
visitor.visit_newtype_struct(self)
|
visitor.visit_newtype_struct(self)
|
||||||
}
|
}
|
||||||
@@ -296,19 +288,19 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
{
|
{
|
||||||
match self.peek_token() {
|
match self.peek_token() {
|
||||||
Token::Unit |
|
Token::Unit |
|
||||||
Token::UnitStruct { name: _ } => {
|
Token::UnitStruct { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
Token::Seq { len: _ } => {
|
Token::Seq { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
||||||
}
|
}
|
||||||
Token::Tuple { len: _ } => {
|
Token::Tuple { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
||||||
}
|
}
|
||||||
Token::TupleStruct { name: _, len: _ } => {
|
Token::TupleStruct { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
||||||
}
|
}
|
||||||
@@ -330,19 +322,19 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
self.next_token();
|
self.next_token();
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
Token::UnitStruct { name: _ } => {
|
Token::UnitStruct { .. } => {
|
||||||
assert_next_token!(self, Token::UnitStruct { name: name });
|
assert_next_token!(self, Token::UnitStruct { name: name });
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
Token::Seq { len: _ } => {
|
Token::Seq { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
||||||
}
|
}
|
||||||
Token::Tuple { len: _ } => {
|
Token::Tuple { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
||||||
}
|
}
|
||||||
Token::TupleStruct { name: _, len: n } => {
|
Token::TupleStruct { len: n, .. } => {
|
||||||
assert_next_token!(self, Token::TupleStruct { name: name, len: n });
|
assert_next_token!(self, Token::TupleStruct { name: name, len: n });
|
||||||
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
||||||
}
|
}
|
||||||
@@ -360,11 +352,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.peek_token() {
|
match self.peek_token() {
|
||||||
Token::Struct { name: _, len: n } => {
|
Token::Struct { len: n, .. } => {
|
||||||
assert_next_token!(self, Token::Struct { name: name, len: n });
|
assert_next_token!(self, Token::Struct { name: name, len: n });
|
||||||
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
|
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
|
||||||
}
|
}
|
||||||
Token::Map { len: _ } => {
|
Token::Map { .. } => {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
|
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
|
||||||
}
|
}
|
||||||
@@ -373,15 +365,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
fn is_human_readable(&self) -> bool {
|
||||||
match self.is_human_readable {
|
panic!(
|
||||||
Some(is) => is,
|
"Types which have different human-readable and compact representations \
|
||||||
None => {
|
must explicitly mark their test cases with `serde_test::Configure`"
|
||||||
panic!("There is no serde_test API currently for testing types \
|
);
|
||||||
that have different human-readable and compact \
|
|
||||||
representation. See \
|
|
||||||
https://github.com/serde-rs/serde/issues/1065.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,10 +448,10 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|||||||
V: DeserializeSeed<'de>,
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
match self.de.peek_token() {
|
match self.de.peek_token() {
|
||||||
Token::UnitVariant { name: _, variant: v } |
|
Token::UnitVariant { variant: v, .. } |
|
||||||
Token::NewtypeVariant { name: _, variant: v } |
|
Token::NewtypeVariant { variant: v, .. } |
|
||||||
Token::TupleVariant { name: _, variant: v, len: _ } |
|
Token::TupleVariant { variant: v, .. } |
|
||||||
Token::StructVariant { name: _, variant: v, len: _ } => {
|
Token::StructVariant { variant: v, .. } => {
|
||||||
let de = v.into_deserializer();
|
let de = v.into_deserializer();
|
||||||
let value = try!(seed.deserialize(de));
|
let value = try!(seed.deserialize(de));
|
||||||
Ok((value, self))
|
Ok((value, self))
|
||||||
@@ -482,7 +469,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|||||||
|
|
||||||
fn unit_variant(self) -> Result<(), Error> {
|
fn unit_variant(self) -> Result<(), Error> {
|
||||||
match self.de.peek_token() {
|
match self.de.peek_token() {
|
||||||
Token::UnitVariant { name: _, variant: _ } => {
|
Token::UnitVariant { .. } => {
|
||||||
self.de.next_token();
|
self.de.next_token();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -495,7 +482,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|||||||
T: DeserializeSeed<'de>,
|
T: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
match self.de.peek_token() {
|
match self.de.peek_token() {
|
||||||
Token::NewtypeVariant { name: _, variant: _ } => {
|
Token::NewtypeVariant { .. } => {
|
||||||
self.de.next_token();
|
self.de.next_token();
|
||||||
seed.deserialize(self.de)
|
seed.deserialize(self.de)
|
||||||
}
|
}
|
||||||
@@ -508,7 +495,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.de.peek_token() {
|
match self.de.peek_token() {
|
||||||
Token::TupleVariant { name: _, variant: _, len: enum_len } => {
|
Token::TupleVariant { len: enum_len, .. } => {
|
||||||
let token = self.de.next_token();
|
let token = self.de.next_token();
|
||||||
|
|
||||||
if len == enum_len {
|
if len == enum_len {
|
||||||
@@ -536,7 +523,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.de.peek_token() {
|
match self.de.peek_token() {
|
||||||
Token::StructVariant { name: _, variant: _, len: enum_len } => {
|
Token::StructVariant { len: enum_len, .. } => {
|
||||||
let token = self.de.next_token();
|
let token = self.de.next_token();
|
||||||
|
|
||||||
if fields.len() == enum_len {
|
if fields.len() == enum_len {
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ pub struct Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Error for Error {
|
impl ser::Error for Error {
|
||||||
fn custom<T: Display>(msg: T) -> Error {
|
fn custom<T: Display>(msg: T) -> Self {
|
||||||
Error { msg: msg.to_string() }
|
Error { msg: msg.to_string() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl de::Error for Error {
|
impl de::Error for Error {
|
||||||
fn custom<T: Display>(msg: T) -> Error {
|
fn custom<T: Display>(msg: T) -> Self {
|
||||||
Error { msg: msg.to_string() }
|
Error { msg: msg.to_string() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-6
@@ -155,7 +155,17 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.17")]
|
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.19")]
|
||||||
|
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
|
// Whitelisted clippy lints
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
||||||
|
// Whitelisted clippy_pedantic lints
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||||
|
missing_docs_in_private_items,
|
||||||
|
stutter,
|
||||||
|
use_self,
|
||||||
|
))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
@@ -164,16 +174,15 @@ mod ser;
|
|||||||
mod de;
|
mod de;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
|
mod configure;
|
||||||
mod token;
|
mod token;
|
||||||
mod assert;
|
mod assert;
|
||||||
|
|
||||||
pub use token::Token;
|
pub use token::Token;
|
||||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error,
|
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
|
||||||
assert_de_tokens, assert_de_tokens_error};
|
assert_ser_tokens_error, assert_tokens};
|
||||||
|
|
||||||
// Not public API.
|
pub use configure::{Compact, Configure, Readable};
|
||||||
#[doc(hidden)]
|
|
||||||
pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable};
|
|
||||||
|
|
||||||
// Not public API.
|
// Not public API.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
+21
-21
@@ -15,19 +15,12 @@ use token::Token;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Serializer<'a> {
|
pub struct Serializer<'a> {
|
||||||
tokens: &'a [Token],
|
tokens: &'a [Token],
|
||||||
is_human_readable: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Serializer<'a> {
|
impl<'a> Serializer<'a> {
|
||||||
/// Creates the serializer.
|
/// Creates the serializer.
|
||||||
pub fn new(tokens: &'a [Token]) -> Self {
|
pub fn new(tokens: &'a [Token]) -> Self {
|
||||||
Serializer::readable(tokens, None)
|
Serializer { tokens: tokens }
|
||||||
}
|
|
||||||
|
|
||||||
// Not public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn readable(tokens: &'a [Token], is_human_readable: Option<bool>) -> Self {
|
|
||||||
Serializer { tokens: tokens, is_human_readable: is_human_readable }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pulls the next token off of the serializer, ignoring it.
|
/// Pulls the next token off of the serializer, ignoring it.
|
||||||
@@ -254,10 +247,16 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
|||||||
assert_next_token!(self, Str(variant));
|
assert_next_token!(self, Str(variant));
|
||||||
let len = Some(len);
|
let len = Some(len);
|
||||||
assert_next_token!(self, Seq { len });
|
assert_next_token!(self, Seq { len });
|
||||||
Ok(Variant { ser: self, end: Token::SeqEnd })
|
Ok(Variant {
|
||||||
|
ser: self,
|
||||||
|
end: Token::SeqEnd,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
assert_next_token!(self, TupleVariant { name, variant, len });
|
assert_next_token!(self, TupleVariant { name, variant, len });
|
||||||
Ok(Variant { ser: self, end: Token::TupleVariantEnd })
|
Ok(Variant {
|
||||||
|
ser: self,
|
||||||
|
end: Token::TupleVariantEnd,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,23 +282,24 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
|||||||
assert_next_token!(self, Str(variant));
|
assert_next_token!(self, Str(variant));
|
||||||
let len = Some(len);
|
let len = Some(len);
|
||||||
assert_next_token!(self, Map { len });
|
assert_next_token!(self, Map { len });
|
||||||
Ok(Variant { ser: self, end: Token::MapEnd })
|
Ok(Variant {
|
||||||
|
ser: self,
|
||||||
|
end: Token::MapEnd,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
assert_next_token!(self, StructVariant { name, variant, len });
|
assert_next_token!(self, StructVariant { name, variant, len });
|
||||||
Ok(Variant { ser: self, end: Token::StructVariantEnd })
|
Ok(Variant {
|
||||||
|
ser: self,
|
||||||
|
end: Token::StructVariantEnd,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
fn is_human_readable(&self) -> bool {
|
||||||
match self.is_human_readable {
|
panic!(
|
||||||
Some(is) => is,
|
"Types which have different human-readable and compact representations \
|
||||||
None => {
|
must explicitly mark their test cases with `serde_test::Configure`"
|
||||||
panic!("There is no serde_test API currently for testing types \
|
);
|
||||||
that have different human-readable and compact \
|
|
||||||
representation. See \
|
|
||||||
https://github.com/serde-rs/serde/issues/1065.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Str<'a>(&'a str);
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
enum Test<'a> {
|
||||||
|
#[serde(borrow)] //~^^ HELP: duplicate serde attribute `borrow`
|
||||||
|
S(#[serde(borrow)] Str<'a>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Str<'a>(&'a str);
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
enum Test<'a> {
|
||||||
|
#[serde(borrow)] //~^^ HELP: #[serde(borrow)] may only be used on newtype variants
|
||||||
|
S { s: Str<'a> }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
+16
-20
@@ -29,7 +29,7 @@ extern crate fnv;
|
|||||||
use self::fnv::FnvHasher;
|
use self::fnv::FnvHasher;
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error, assert_de_tokens_readable};
|
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@@ -49,16 +49,14 @@ struct TupleStruct(i32, i32, i32);
|
|||||||
struct Struct {
|
struct Struct {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)] c: i32,
|
||||||
c: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct StructDenyUnknown {
|
struct StructDenyUnknown {
|
||||||
a: i32,
|
a: i32,
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)] b: i32,
|
||||||
b: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
@@ -79,15 +77,13 @@ impl Default for StructDefault<String> {
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
struct StructSkipAll {
|
struct StructSkipAll {
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)] a: i32,
|
||||||
a: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct StructSkipAllDenyUnknown {
|
struct StructSkipAllDenyUnknown {
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)] a: i32,
|
||||||
a: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
@@ -112,7 +108,7 @@ enum EnumSkipAll {
|
|||||||
|
|
||||||
macro_rules! declare_tests {
|
macro_rules! declare_tests {
|
||||||
(
|
(
|
||||||
readable: $readable:tt
|
$readable:tt
|
||||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
@@ -120,7 +116,7 @@ macro_rules! declare_tests {
|
|||||||
fn $name() {
|
fn $name() {
|
||||||
$(
|
$(
|
||||||
// Test ser/de roundtripping
|
// Test ser/de roundtripping
|
||||||
assert_de_tokens_readable(&$value, $tokens, Some($readable));
|
assert_de_tokens(&$value.$readable(), $tokens);
|
||||||
|
|
||||||
// Test that the tokens are ignorable
|
// Test that the tokens are ignorable
|
||||||
assert_de_tokens_ignore($tokens);
|
assert_de_tokens_ignore($tokens);
|
||||||
@@ -168,13 +164,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
|
|||||||
Token::Map { len: Some(2) },
|
Token::Map { len: Some(2) },
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::Str("ignored"),
|
Token::Str("ignored"),
|
||||||
]
|
].into_iter()
|
||||||
.into_iter()
|
.chain(ignorable_tokens.to_vec().into_iter())
|
||||||
.chain(ignorable_tokens.to_vec().into_iter())
|
.chain(vec![Token::MapEnd].into_iter())
|
||||||
.chain(vec![Token::MapEnd].into_iter())
|
.collect();
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut de = serde_test::Deserializer::new(&concated_tokens);
|
let mut de = serde_test::Deserializer::new(&concated_tokens);
|
||||||
let base = IgnoreBase::deserialize(&mut de).unwrap();
|
let base = IgnoreBase::deserialize(&mut de).unwrap();
|
||||||
@@ -774,7 +768,8 @@ declare_tests! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
readable: true
|
readable
|
||||||
|
|
||||||
test_net_ipv4addr_readable {
|
test_net_ipv4addr_readable {
|
||||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||||
}
|
}
|
||||||
@@ -792,7 +787,8 @@ declare_tests! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
readable: false
|
compact
|
||||||
|
|
||||||
test_net_ipv4addr_compact {
|
test_net_ipv4addr_compact {
|
||||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||||
Token::Tuple { len: 4 },
|
Token::Tuple { len: 4 },
|
||||||
@@ -1180,7 +1176,7 @@ declare_error_tests! {
|
|||||||
}
|
}
|
||||||
test_wrapping_overflow<Wrapping<u16>> {
|
test_wrapping_overflow<Wrapping<u16>> {
|
||||||
&[
|
&[
|
||||||
Token::U32(65536),
|
Token::U32(65_536),
|
||||||
],
|
],
|
||||||
"invalid value: integer `65536`, expected u16",
|
"invalid value: integer `65536`, expected u16",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,6 @@
|
|||||||
|
|
||||||
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
|
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
|
||||||
|
|
||||||
// Clippy false positive
|
|
||||||
// https://github.com/Manishearth/rust-clippy/issues/292
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
@@ -361,6 +357,12 @@ fn test_gen() {
|
|||||||
s: Str<'a>,
|
s: Str<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
enum BorrowVariant<'a> {
|
||||||
|
#[serde(borrow, with = "StrDef")]
|
||||||
|
S(Str<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
mod vis {
|
mod vis {
|
||||||
pub struct S;
|
pub struct S;
|
||||||
|
|
||||||
@@ -515,6 +517,25 @@ fn test_gen() {
|
|||||||
Tuple(&'a str, &'static str),
|
Tuple(&'a str, &'static str),
|
||||||
Newtype(&'static str),
|
Newtype(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct SkippedStaticStr {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
skipped: &'static str,
|
||||||
|
other: isize,
|
||||||
|
}
|
||||||
|
assert::<SkippedStaticStr>();
|
||||||
|
|
||||||
|
macro_rules! T {
|
||||||
|
() => { () }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct TypeMacro<T> {
|
||||||
|
mac: T!(),
|
||||||
|
marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
assert::<TypeMacro<X>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -9,10 +9,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use serde_test::{Token, assert_de_tokens};
|
use serde_test::{assert_de_tokens, Token};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_variant_identifier() {
|
fn test_variant_identifier() {
|
||||||
@@ -51,8 +49,7 @@ fn test_unit_fallthrough() {
|
|||||||
enum F {
|
enum F {
|
||||||
Aaa,
|
Aaa,
|
||||||
Bbb,
|
Bbb,
|
||||||
#[serde(other)]
|
#[serde(other)] Other,
|
||||||
Other,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&F::Other, &[Token::Str("x")]);
|
assert_de_tokens(&F::Other, &[Token::Str("x")]);
|
||||||
|
|||||||
@@ -1267,3 +1267,48 @@ fn test_rename_all() {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_untagged_newtype_variant_containing_unit_struct_not_map() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Unit;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Message {
|
||||||
|
Unit(Unit),
|
||||||
|
Map(BTreeMap<String, String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Message::Map(BTreeMap::new()),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(0) },
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_internally_tagged_newtype_variant_containing_unit_struct() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Info;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "topic")]
|
||||||
|
enum Message {
|
||||||
|
Info(Info),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Message::Info(Info),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
|
||||||
|
Token::Str("topic"),
|
||||||
|
Token::Str("Info"),
|
||||||
|
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
mod remote {
|
mod remote {
|
||||||
pub struct Unit;
|
pub struct Unit;
|
||||||
|
|
||||||
@@ -87,32 +85,23 @@ mod remote {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Test {
|
struct Test {
|
||||||
#[serde(with = "UnitDef")]
|
#[serde(with = "UnitDef")] unit: remote::Unit,
|
||||||
unit: remote::Unit,
|
|
||||||
|
|
||||||
#[serde(with = "PrimitivePrivDef")]
|
#[serde(with = "PrimitivePrivDef")] primitive_priv: remote::PrimitivePriv,
|
||||||
primitive_priv: remote::PrimitivePriv,
|
|
||||||
|
|
||||||
#[serde(with = "PrimitivePubDef")]
|
#[serde(with = "PrimitivePubDef")] primitive_pub: remote::PrimitivePub,
|
||||||
primitive_pub: remote::PrimitivePub,
|
|
||||||
|
|
||||||
#[serde(with = "NewtypePrivDef")]
|
#[serde(with = "NewtypePrivDef")] newtype_priv: remote::NewtypePriv,
|
||||||
newtype_priv: remote::NewtypePriv,
|
|
||||||
|
|
||||||
#[serde(with = "NewtypePubDef")]
|
#[serde(with = "NewtypePubDef")] newtype_pub: remote::NewtypePub,
|
||||||
newtype_pub: remote::NewtypePub,
|
|
||||||
|
|
||||||
#[serde(with = "TuplePrivDef")]
|
#[serde(with = "TuplePrivDef")] tuple_priv: remote::TuplePriv,
|
||||||
tuple_priv: remote::TuplePriv,
|
|
||||||
|
|
||||||
#[serde(with = "TuplePubDef")]
|
#[serde(with = "TuplePubDef")] tuple_pub: remote::TuplePub,
|
||||||
tuple_pub: remote::TuplePub,
|
|
||||||
|
|
||||||
#[serde(with = "StructPrivDef")]
|
#[serde(with = "StructPrivDef")] struct_priv: remote::StructPriv,
|
||||||
struct_priv: remote::StructPriv,
|
|
||||||
|
|
||||||
#[serde(with = "StructPubDef")]
|
#[serde(with = "StructPubDef")] struct_pub: remote::StructPub,
|
||||||
struct_pub: remote::StructPub,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -121,10 +110,7 @@ struct UnitDef;
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::PrimitivePriv")]
|
#[serde(remote = "remote::PrimitivePriv")]
|
||||||
struct PrimitivePrivDef(
|
struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
|
||||||
#[serde(getter = "remote::PrimitivePriv::get")]
|
|
||||||
u8
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::PrimitivePub")]
|
#[serde(remote = "remote::PrimitivePub")]
|
||||||
@@ -133,53 +119,41 @@ struct PrimitivePubDef(u8);
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::NewtypePriv")]
|
#[serde(remote = "remote::NewtypePriv")]
|
||||||
struct NewtypePrivDef(
|
struct NewtypePrivDef(
|
||||||
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")]
|
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit,
|
||||||
remote::Unit
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::NewtypePub")]
|
#[serde(remote = "remote::NewtypePub")]
|
||||||
struct NewtypePubDef(
|
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
|
||||||
#[serde(with = "UnitDef")]
|
|
||||||
remote::Unit
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::TuplePriv")]
|
#[serde(remote = "remote::TuplePriv")]
|
||||||
struct TuplePrivDef(
|
struct TuplePrivDef(
|
||||||
#[serde(getter = "remote::TuplePriv::first")]
|
#[serde(getter = "remote::TuplePriv::first")] u8,
|
||||||
u8,
|
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit,
|
||||||
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")]
|
|
||||||
remote::Unit
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::TuplePub")]
|
#[serde(remote = "remote::TuplePub")]
|
||||||
struct TuplePubDef(
|
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
|
||||||
u8,
|
|
||||||
#[serde(with = "UnitDef")]
|
|
||||||
remote::Unit
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::StructPriv")]
|
#[serde(remote = "remote::StructPriv")]
|
||||||
struct StructPrivDef {
|
struct StructPrivDef {
|
||||||
#[serde(getter = "remote::StructPriv::a")]
|
#[serde(getter = "remote::StructPriv::a")] a: u8,
|
||||||
a: u8,
|
|
||||||
|
|
||||||
#[serde(getter = "remote::StructPriv::b")]
|
#[serde(getter = "remote::StructPriv::b")]
|
||||||
#[serde(with= "UnitDef")]
|
#[serde(with = "UnitDef")]
|
||||||
b: remote::Unit,
|
b: remote::Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::StructPub")]
|
#[serde(remote = "remote::StructPub")]
|
||||||
struct StructPubDef {
|
struct StructPubDef {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)] a: u8,
|
||||||
a: u8,
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[serde(with= "UnitDef")]
|
#[serde(with = "UnitDef")]
|
||||||
b: remote::Unit,
|
b: remote::Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use self::serde_test::{Token, assert_tokens_readable};
|
use self::serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use std::net;
|
use std::net;
|
||||||
|
|
||||||
@@ -17,9 +17,8 @@ mod macros;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ip_addr_roundtrip() {
|
fn ip_addr_roundtrip() {
|
||||||
|
assert_tokens(
|
||||||
assert_tokens_readable(
|
&net::IpAddr::from(*b"1234").compact(),
|
||||||
&net::IpAddr::from(*b"1234"),
|
|
||||||
&seq![
|
&seq![
|
||||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||||
|
|
||||||
@@ -27,15 +26,13 @@ fn ip_addr_roundtrip() {
|
|||||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
],
|
],
|
||||||
Some(false),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn socked_addr_roundtrip() {
|
fn socked_addr_roundtrip() {
|
||||||
|
assert_tokens(
|
||||||
assert_tokens_readable(
|
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
|
||||||
&net::SocketAddr::from((*b"1234567890123456", 1234)),
|
|
||||||
&seq![
|
&seq![
|
||||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||||
|
|
||||||
@@ -48,6 +45,5 @@ fn socked_addr_roundtrip() {
|
|||||||
Token::U16(1234),
|
Token::U16(1234),
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
],
|
],
|
||||||
Some(false),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,8 @@ use std::num::Wrapping;
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error,
|
use self::serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
|
||||||
assert_ser_tokens_readable};
|
|
||||||
|
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
use self::fnv::FnvHasher;
|
use self::fnv::FnvHasher;
|
||||||
@@ -54,28 +51,24 @@ enum Enum {
|
|||||||
One(i32),
|
One(i32),
|
||||||
Seq(i32, i32),
|
Seq(i32, i32),
|
||||||
Map { a: i32, b: i32 },
|
Map { a: i32, b: i32 },
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)] SkippedUnit,
|
||||||
SkippedUnit,
|
#[serde(skip_serializing)] SkippedOne(i32),
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)] SkippedSeq(i32, i32),
|
||||||
SkippedOne(i32),
|
#[serde(skip_serializing)] SkippedMap { _a: i32, _b: i32 },
|
||||||
#[serde(skip_serializing)]
|
|
||||||
SkippedSeq(i32, i32),
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
SkippedMap { _a: i32, _b: i32 },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! declare_tests {
|
macro_rules! declare_tests {
|
||||||
(
|
(
|
||||||
readable: $readable:tt
|
$readable:tt
|
||||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
$(
|
$(
|
||||||
assert_ser_tokens_readable(&$value, $tokens, Some($readable));
|
assert_ser_tokens(&$value.$readable(), $tokens);
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
@@ -408,7 +401,8 @@ declare_tests! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
readable: true
|
readable
|
||||||
|
|
||||||
test_net_ipv4addr_readable {
|
test_net_ipv4addr_readable {
|
||||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||||
}
|
}
|
||||||
@@ -426,7 +420,8 @@ declare_tests! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
readable: false
|
compact
|
||||||
|
|
||||||
test_net_ipv4addr_compact {
|
test_net_ipv4addr_compact {
|
||||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||||
Token::Tuple { len: 4 },
|
Token::Tuple { len: 4 },
|
||||||
@@ -524,11 +519,7 @@ fn test_cannot_serialize_paths() {
|
|||||||
let mut path_buf = PathBuf::new();
|
let mut path_buf = PathBuf::new();
|
||||||
path_buf.push(path);
|
path_buf.push(path);
|
||||||
|
|
||||||
assert_ser_tokens_error(
|
assert_ser_tokens_error(&path_buf, &[], "path contains invalid UTF-8 characters");
|
||||||
&path_buf,
|
|
||||||
&[],
|
|
||||||
"path contains invalid UTF-8 characters",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ if [ -n "${CLIPPY}" ]; then
|
|||||||
cd "$DIR/serde_derive"
|
cd "$DIR/serde_derive"
|
||||||
cargo clippy -- -Dclippy
|
cargo clippy -- -Dclippy
|
||||||
|
|
||||||
|
cd "$DIR/serde_test"
|
||||||
|
cargo clippy -- -Dclippy
|
||||||
|
|
||||||
cd "$DIR/test_suite"
|
cd "$DIR/test_suite"
|
||||||
cargo clippy --features unstable -- -Dclippy
|
cargo clippy --features unstable -- -Dclippy
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user