Compare commits

...

35 Commits

Author SHA1 Message Date
David Tolnay 88d5fe6bfd Release 1.0.19 2017-11-06 23:50:24 -08:00
David Tolnay 9a2c352025 Rephrase serde_test::Configure documentation 2017-11-06 23:47:39 -08:00
David Tolnay 61c90cb8cb Fix typo in serde_test::Configure documentation 2017-11-06 23:45:26 -08:00
David Tolnay 66e8b0a0cd Merge pull request #1085 from serde-rs/internally-unit-struct
Allow internally tagged newtype variant containing unit struct
2017-11-06 23:44:29 -08:00
David Tolnay 9e7a3437d9 Allow internally tagged newtype variant containing unit struct 2017-11-06 23:32:36 -08:00
David Tolnay 7ac8d4f9ae AsciiExt transition 2017-11-06 22:50:10 -08:00
David Tolnay 501bae42f5 Fix space in serde_test panic message
Without this, the message contains "representationsmust".
2017-11-06 22:46:28 -08:00
David Tolnay 7a0397451e Allow serde_test::Configure to be dynamically sized
This is a more cautious choice for the trait. In the future we may need
a `whatever_ref(&self)` that works for !Sized types.
2017-11-06 22:40:09 -08:00
David Tolnay 16787318d1 Enable clippy_pedantic in serde_test 2017-11-06 22:31:35 -08:00
David Tolnay f4ae0888c8 Run clippy on serde_test in Travis 2017-11-06 22:28:58 -08:00
David Tolnay 213071fe5c Combine identical match arms in serde_test
As recommended by Clippy's match_same_arms lint.
2017-11-06 22:27:51 -08:00
David Tolnay cfd26c6fda Avoid cloning Copy types
As recommended by Clippy's clone_on_copy lint.
2017-11-06 22:26:55 -08:00
David Tolnay 23fa83941e Whitelist float_cmp lint in serde_test 2017-11-06 22:26:01 -08:00
David Tolnay 88f5b9511d Use .. in patterns
As recommended by Clippy's unneeded_field_pattern lint.
2017-11-06 22:24:25 -08:00
David Tolnay d537f1e1f0 Whitelist needless_pass_by_value lint
This lint has a false positive on trait methods with a default implementation.
2017-11-06 22:10:11 -08:00
David Tolnay f6ac232580 Merge pull request #1084 from Marwes/serde_test_readable_
Add an API for making tests for readable/compact representations
2017-11-06 22:05:29 -08:00
Markus Westerlind aad7a7987f Add an example to the Configure trait 2017-11-06 10:35:22 +01:00
David Tolnay b24ad76880 Merge pull request #1080 from xfix/patch-2
serde_test requires serde 1.0.16 to work
2017-11-05 15:03:28 -08:00
Konrad Borowski 5796f1a0f5 serde_test requires serde 1.0.16 to work
This is due to implementing is_human_readable which was
added in serde 1.0.16.
2017-11-05 23:51:01 +01:00
David Tolnay 6437167930 Merge pull request #1083 from serde-rs/ty-macro
Fix bounds for macro named the same as a type parameter
2017-11-05 12:56:57 -08:00
David Tolnay f98daaa250 Merge pull request #1082 from serde-rs/borrow-variant
Allow borrow attribute on newtype variants
2017-11-05 12:20:40 -08:00
David Tolnay b8a40551a2 Fix bounds for macro named the same as a type parameter 2017-11-05 12:18:39 -08:00
David Tolnay 40db31691a Allow borrow attribute on newtype variants 2017-11-05 12:10:40 -08:00
David Tolnay ab68132b1f Release 1.0.18 2017-11-03 10:20:41 -07:00
David Tolnay e70bbd9dde Merge pull request #1079 from serde-rs/skipborrow
Ignore skipped fields when looking for borrowed lifetimes
2017-11-03 10:20:32 -07:00
David Tolnay d5e5c520ac Ignore skipped fields when looking for borrowed lifetimes 2017-11-03 10:08:02 -07:00
Markus Westerlind 1b9a096fa7 Export configure api 2017-11-02 16:03:50 +01:00
Markus Westerlind 39e05ffad2 Implement Deserializer for Readable/Compact 2017-11-02 15:47:07 +01:00
Markus Westerlind 78fab25c5c implement Serializer for Readable/Compact 2017-11-02 15:47:07 +01:00
David Tolnay 2a557a1e36 Clippy false positive on needless_lifetimes has been fixed 2017-10-31 22:42:53 -07:00
David Tolnay ab0848f780 Follow clippy advice about unreadable literal 2017-10-31 22:42:12 -07:00
David Tolnay 2b1303f59c Whitelist const_static_lifetime
This clippy suggestion is not stable in the older rustc we support.
2017-10-31 22:23:39 -07:00
David Tolnay 7f9ba155cb Explain what each dependency is for 2017-10-31 22:16:33 -07:00
David Tolnay a4e0c2f055 Merge pull request #1075 from hcpl/clarify-readme-example
Clarify the README example for local builds
2017-10-31 22:16:15 -07:00
hcpl 3bbf70575b Clarify the README example for local builds 2017-10-31 21:20:23 +02:00
31 changed files with 1029 additions and 254 deletions
+24 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
} }
} }
+3 -3
View File
@@ -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(
+2 -2
View File
@@ -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]
+8
View File
@@ -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
+3 -1
View File
@@ -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
+1 -1
View File
@@ -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 -1
View File
@@ -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."
+10 -9
View File
@@ -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,
} }
}, },
+23 -2
View File
@@ -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")]`
+3
View File
@@ -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::*;
+1 -1
View File
@@ -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]
+3 -3
View File
@@ -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]
+5 -38
View File
@@ -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),
+661
View File
@@ -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
View File
@@ -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 {
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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",
} }
+25 -4
View File
@@ -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>>();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
+2 -5
View File
@@ -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")]);
+45
View File
@@ -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,
],
);
}
+19 -45
View File
@@ -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,
} }
+5 -9
View File
@@ -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),
); );
} }
+12 -21
View File
@@ -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]
+3
View File
@@ -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