Compare commits

...

82 Commits

Author SHA1 Message Date
David Tolnay ae59c6b6d2 Release 1.0.25 2017-12-23 23:33:59 -05:00
David Tolnay 4973d7a62d Suppress errors on rustfmt line overflow
Some of the serde_derive lines inside of quote!(...) are too long. Rustfmt
cannot fix these. Will need to follow up.
2017-12-23 20:27:56 -08:00
David Tolnay ed6a1de311 Auto format attributes on their own line 2017-12-23 20:24:57 -08:00
David Tolnay ab234be025 The rustfmt rfc style is now the default 2017-12-23 20:21:52 -08:00
David Tolnay ee75e6c0e9 Format with rustfmt-nightly 0.3.4 2017-12-23 20:17:52 -08:00
David Tolnay c2b390fe63 Merge pull request #1124 from serde-rs/in-place
Rename deserialize_from to deserialize_in_place
2017-12-23 19:56:29 -08:00
David Tolnay 56d5d7f761 Rename deserialize_from to deserialize_in_place 2017-12-17 10:46:44 -08:00
David Tolnay 0b89bc920e Merge pull request #1094 from Gankro/deserialize_from
Add and derive deserialize_from
2017-12-11 21:29:15 -08:00
David Tolnay 0dac13e4db Resolve conflict with pr 1115 2017-12-11 20:59:54 -08:00
David Tolnay 0c2e91f28a Merge branch serde-rs/master into Gankro/deserialize_from 2017-12-11 20:49:23 -08:00
David Tolnay 13e7bee0e6 Eliminate need for unwrap in deserialize_from_seq 2017-12-11 18:13:13 -08:00
David Tolnay 65104aca9c Remove need for allow(unreachable_code) 2017-12-11 17:55:23 -08:00
David Tolnay 9360094ba7 Revert main_body naming change
The naming here isn't great but no need to change it in this PR.
2017-12-10 23:19:31 -08:00
David Tolnay 3700779bfa More meaningful names and types for nop_reserve 2017-12-10 23:18:08 -08:00
David Tolnay d9e894911f Move all the deserialize_from derive code behind flag 2017-12-10 23:15:14 -08:00
David Tolnay 85e3ddc2b8 Less indentiation in deserialize_from_body 2017-12-10 23:04:44 -08:00
David Tolnay ccae35d92a Do not emit deserialize_from if every field has deserialize_with 2017-12-10 22:55:28 -08:00
David Tolnay 61ca928325 Can never see getters in a deserialize_from 2017-12-10 22:46:46 -08:00
David Tolnay a93f2ebff0 Enable deserialize_from in the test suite 2017-12-10 22:46:25 -08:00
David Tolnay a45f1ae915 Remove unused dev-dependency of serde_test on deserialize_from 2017-12-10 22:02:11 -08:00
David Tolnay 9641978481 Hide deserialize_from 2017-12-10 21:55:07 -08:00
David Tolnay ffd2017c6f Use the default deserialize_from for Option<T>
The custom one was functionally identical to the default implementation given by
the Deserialize trait. If someone has benchmarks that the custom one performs
better, we can put it back.
2017-12-10 21:27:44 -08:00
David Tolnay b7eb42aa6b Release 1.0.24 2017-12-09 14:43:55 -08:00
David Tolnay 750f8ba299 Clean up trailing whitespace 2017-12-09 14:42:59 -08:00
David Tolnay 49cdef074d Merge pull request #1115 from Binero/master
Solved #1105.
2017-12-08 08:57:31 -08:00
Jeroen Bollen aa86b04714 Adressed concerns raised by @oli-obk.
Specifically:
 - Change identation in `de.rs`.
 - Make `attr::Field` take a `attr::Default` as opposed to the entire parent `attr::Container`.
2017-12-08 15:13:05 +01:00
Jeroen Bollen c887a0b472 Solved #1105.
When a field should be skipped during deserialization, it will not use its own Default implementation
when the container structure has `#[serde(default)]` set.
2017-12-06 21:14:02 +01:00
Alexis Beingessner 34936be574 test deserialize_from 2017-12-04 13:29:03 -05:00
Alexis Beingessner e354dd0c7f Derive deserialize_from for tuples and structs
This adds a new "deserialize_from" feature (default off) that opts into
deriving deserialize_from with #[derive(Deserialize)].
2017-12-04 13:23:26 -05:00
Alexis Beingessner bc221abb04 Augment builtin std/core Deserialize impls to implement deserialize_from 2017-12-04 13:23:26 -05:00
Alexis Beingessner ab5e8780ab Add deserialize_from to Deserialize 2017-12-04 13:23:26 -05:00
David Tolnay 0c34e06e51 Merge pull request #1106 from khuey/inlines
Inline various deserialization helper methods.
2017-12-02 15:57:07 -08:00
Kyle Huey 4a0c4e0c25 Mark size_hint::cautious as inline. 2017-12-01 14:31:52 -08:00
David Tolnay 8c34e0940f Release 1.0.23 2017-11-29 22:26:32 -08:00
David Tolnay eb6bf16a51 Revert "Catch wrong field names length in serde_test"
There are at least two reasonable things to expect the len field to
check: the length of the fields array passed to deserialize_struct, or
the number of field tokens. Even beyond these, in some cases it can be
useful to test deserialization with a bogus len to test how the
Deserialize impl reacts to an incorrect size_hint.

This reverts commit 436cafb0a3 which was
released in serde_test 1.0.20.
2017-11-29 22:21:05 -08:00
David Tolnay 797d049db5 Release 1.0.22 2017-11-29 20:01:43 -08:00
David Tolnay d61a373f12 Merge pull request #1104 from serde-rs/abs
Fix missing absolute paths in deserialize_seq
2017-11-29 19:58:21 -08:00
David Tolnay e0eea551b4 Fix missing absolute paths in deserialize_seq 2017-11-29 19:45:22 -08:00
David Tolnay c650a92bf7 Update to compiletest-rs 0.3 to fix "every suggestion should have at least one span" 2017-11-24 17:12:58 -08:00
David Tolnay f218f4d7bf Release 1.0.21 2017-11-15 22:24:18 -08:00
Alex Shapiro 8c0a2015be Fix error when deserializing untagged enum
Serde's `ContentDeserializer` and `ContentRefDeserializer`
cannot deserialize struct enum variant associated data when
that data is encoded as a sequence. This failure leads to
errors when decoding an enum nested in another untagged
enum. For example:

    #[derive(Serialize, Deserialize)]
    #[serde(untagged)]
    enum Foo {
        A(Bar),
    }

    #[derive(Serialize, Deserialize)]
    enum Bar {
        B{f1: String},
    }

    let data1 = Foo::A(Bar::B{f1: "Hello".into()});
    let bytes = rmp_serde::to_vec(&data1).unwrap();
    let data2 = rmp_serde::from_slice::<Foo>(&bytes).unwrap();

Deserializing fails with the error `Syntax("data did not
match any variant of untagged enum Foo")`, but the
underlying failure occurs when decoding the associated data
of `Bar::B`.

This pull request fixes the issue by allowing
`ContentDeserializer` and `ContentRefDeserializer` to
deserialize sequence-encoded struct enum variant data.
2017-11-15 21:56:33 -08:00
David Tolnay 4773863e3a Release 1.0.20 2017-11-12 10:29:08 -08:00
David Tolnay 80cd9c7617 Merge pull request #1091 from serde-rs/fields-len
Catch wrong field names length in serde_test
2017-11-12 10:28:26 -08:00
David Tolnay 436cafb0a3 Catch wrong field names length in serde_test 2017-11-12 10:16:43 -08:00
David Tolnay 98bb02e9b4 Whitelist use of Debug in serde_test 2017-11-07 10:00:18 -08:00
David Tolnay 142439088c Merge pull request #1086 from Marwes/better_errors
Print the contents of the expected token when a serialize assert fails
2017-11-07 09:53:58 -08:00
Markus Westerlind ce81288235 Print the contents of the expected token when a serialize assert fails
Before
```
expected Token::Str but serialized as Str(“F9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4")
```
After
```
expected Token::Str(“f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4”) but serialized as Str(“F9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4")
```
2017-11-07 14:22:42 +01:00
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
48 changed files with 3932 additions and 1913 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]
+2 -5
View File
@@ -1,5 +1,2 @@
fn_args_layout = "Block" error_on_line_overflow = false
array_layout = "Block" same_line_attributes = false
where_style = "Rfc"
generics_indent = "Block"
fn_call_style = "Block"
+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.25" # 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"
+1 -1
View File
@@ -8,7 +8,7 @@
use lib::*; use lib::*;
use de::{Deserialize, Deserializer, Visitor, SeqAccess, MapAccess, Error}; use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
/// An efficient way of discarding data from a deserializer. /// An efficient way of discarding data from a deserializer.
/// ///
+299 -80
View File
@@ -15,6 +15,7 @@ use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, Va
use de::MapAccess; use de::MapAccess;
use de::from_primitive::FromPrimitive; use de::from_primitive::FromPrimitive;
use private::de::InPlaceSeed;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use private::de::size_hint; use private::de::size_hint;
@@ -210,6 +211,8 @@ impl<'de> Deserialize<'de> for char {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
struct StringVisitor; struct StringVisitor;
#[cfg(any(feature = "std", feature = "alloc"))]
struct StringInPlaceVisitor<'a>(&'a mut String);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Visitor<'de> for StringVisitor { impl<'de> Visitor<'de> for StringVisitor {
@@ -249,7 +252,66 @@ impl<'de> Visitor<'de> for StringVisitor {
{ {
match String::from_utf8(v) { match String::from_utf8(v) {
Ok(s) => Ok(s), Ok(s) => Ok(s),
Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self),), Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, v: &str) -> Result<(), E>
where
E: Error,
{
self.0.clear();
self.0.push_str(v);
Ok(())
}
fn visit_string<E>(self, v: String) -> Result<(), E>
where
E: Error,
{
*self.0 = v;
Ok(())
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<(), E>
where
E: Error,
{
match str::from_utf8(v) {
Ok(s) => {
self.0.clear();
self.0.push_str(s);
Ok(())
}
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
}
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<(), E>
where
E: Error,
{
match String::from_utf8(v) {
Ok(s) => {
*self.0 = s;
Ok(())
}
Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
} }
} }
} }
@@ -262,6 +324,13 @@ impl<'de> Deserialize<'de> for String {
{ {
deserializer.deserialize_string(StringVisitor) deserializer.deserialize_string(StringVisitor)
} }
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_string(StringInPlaceVisitor(place))
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -465,8 +534,16 @@ where
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
deserializer.deserialize_option(OptionVisitor { marker: PhantomData }) deserializer.deserialize_option(OptionVisitor {
marker: PhantomData,
})
} }
// The Some variant's repr is opaque, so we can't play cute tricks with its
// tag to have deserialize_in_place build the content in place unconditionally.
//
// FIXME: investigate whether branching on the old value being Some to
// deserialize_in_place the value is profitable (probably data-dependent?)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -496,7 +573,9 @@ impl<'de, T> Deserialize<'de> for PhantomData<T> {
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let visitor = PhantomDataVisitor { marker: PhantomData }; let visitor = PhantomDataVisitor {
marker: PhantomData,
};
deserializer.deserialize_unit_struct("PhantomData", visitor) deserializer.deserialize_unit_struct("PhantomData", visitor)
} }
} }
@@ -509,7 +588,9 @@ macro_rules! seq_impl {
$ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
$access:ident, $access:ident,
$ctor:expr, $ctor:expr,
$clear:expr,
$with_capacity:expr, $with_capacity:expr,
$reserve:expr,
$insert:expr $insert:expr
) => { ) => {
impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty<T $(, $typaram)*> impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty<T $(, $typaram)*>
@@ -554,16 +635,59 @@ macro_rules! seq_impl {
let visitor = SeqVisitor { marker: PhantomData }; let visitor = SeqVisitor { marker: PhantomData };
deserializer.deserialize_seq(visitor) deserializer.deserialize_seq(visitor)
} }
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct SeqInPlaceVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty<T $(, $typaram)*>);
impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqInPlaceVisitor<'a, T $(, $typaram)*>
where
T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*,
$($typaram: $bound1 $(+ $bound2)*,)*
{
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence")
}
#[inline]
fn visit_seq<A>(mut self, mut $access: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
$clear(&mut self.0);
$reserve(&mut self.0, size_hint::cautious($access.size_hint()));
// FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList)
while let Some(value) = try!($access.next_element()) {
$insert(&mut self.0, value);
}
Ok(())
}
}
deserializer.deserialize_seq(SeqInPlaceVisitor(place))
}
} }
} }
} }
// Dummy impl of reserve
#[cfg(any(feature = "std", feature = "alloc"))]
fn nop_reserve<T>(_seq: T, _n: usize) {}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
BinaryHeap<T: Ord>, BinaryHeap<T: Ord>,
seq, seq,
BinaryHeap::new(), BinaryHeap::new(),
BinaryHeap::clear,
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::reserve,
BinaryHeap::push); BinaryHeap::push);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
@@ -571,7 +695,9 @@ seq_impl!(
BTreeSet<T: Eq + Ord>, BTreeSet<T: Eq + Ord>,
seq, seq,
BTreeSet::new(), BTreeSet::new(),
BTreeSet::clear,
BTreeSet::new(), BTreeSet::new(),
nop_reserve,
BTreeSet::insert); BTreeSet::insert);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
@@ -579,15 +705,20 @@ seq_impl!(
LinkedList<T>, LinkedList<T>,
seq, seq,
LinkedList::new(), LinkedList::new(),
LinkedList::clear,
LinkedList::new(), LinkedList::new(),
LinkedList::push_back); nop_reserve,
LinkedList::push_back
);
#[cfg(feature = "std")] #[cfg(feature = "std")]
seq_impl!( seq_impl!(
HashSet<T: Eq + Hash, S: BuildHasher + Default>, HashSet<T: Eq + Hash, S: BuildHasher + Default>,
seq, seq,
HashSet::with_hasher(S::default()), HashSet::with_hasher(S::default()),
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert); HashSet::insert);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
@@ -595,26 +726,35 @@ seq_impl!(
Vec<T>, Vec<T>,
seq, seq,
Vec::new(), Vec::new(),
Vec::clear,
Vec::with_capacity(size_hint::cautious(seq.size_hint())), Vec::with_capacity(size_hint::cautious(seq.size_hint())),
Vec::push); Vec::reserve,
Vec::push
);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
VecDeque<T>, VecDeque<T>,
seq, seq,
VecDeque::new(), VecDeque::new(),
VecDeque::clear,
VecDeque::with_capacity(size_hint::cautious(seq.size_hint())), VecDeque::with_capacity(size_hint::cautious(seq.size_hint())),
VecDeque::push_back); VecDeque::reserve,
VecDeque::push_back
);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
struct ArrayVisitor<A> { struct ArrayVisitor<A> {
marker: PhantomData<A>, marker: PhantomData<A>,
} }
struct ArrayInPlaceVisitor<'a, A: 'a>(&'a mut A);
impl<A> ArrayVisitor<A> { impl<A> ArrayVisitor<A> {
fn new() -> Self { fn new() -> Self {
ArrayVisitor { marker: PhantomData } ArrayVisitor {
marker: PhantomData,
}
} }
} }
@@ -673,6 +813,35 @@ macro_rules! array_impls {
} }
} }
impl<'a, 'de, T> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; $len]>
where
T: Deserialize<'de>,
{
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("an array of length ", $len))
}
#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
let mut fail_idx = None;
for (idx, dest) in self.0[..].iter_mut().enumerate() {
if try!(seq.next_element_seed(InPlaceSeed(dest))).is_none() {
fail_idx = Some(idx);
break;
}
}
if let Some(idx) = fail_idx {
return Err(Error::invalid_length(idx, &self));
}
Ok(())
}
}
impl<'de, T> Deserialize<'de> for [T; $len] impl<'de, T> Deserialize<'de> for [T; $len]
where where
T: Deserialize<'de>, T: Deserialize<'de>,
@@ -683,6 +852,13 @@ macro_rules! array_impls {
{ {
deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new()) deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new())
} }
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple($len, ArrayInPlaceVisitor(place))
}
} }
)+ )+
} }
@@ -726,49 +902,76 @@ array_impls! {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
macro_rules! tuple_impls { macro_rules! tuple_impls {
($($len:tt $visitor:ident => ($($n:tt $name:ident)+))+) => { ($($len:tt => ($($n:tt $name:ident)+))+) => {
$( $(
struct $visitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<$($name,)+> $visitor<$($name,)+> {
fn new() -> Self {
$visitor { marker: PhantomData }
}
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for $visitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<($($name,)+), A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match try!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) { impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) {
#[inline] #[inline]
fn deserialize<D>(deserializer: D) -> Result<($($name,)+), D::Error> fn deserialize<D>(deserializer: D) -> Result<($($name,)+), D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
deserializer.deserialize_tuple($len, $visitor::new()) struct TupleVisitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<($($name,)+), A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match try!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData })
}
#[inline]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+));
impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
$(
if try!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() {
return Err(Error::invalid_length($n, &self));
}
)+
Ok(())
}
}
deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place))
} }
} }
)+ )+
@@ -776,22 +979,22 @@ macro_rules! tuple_impls {
} }
tuple_impls! { tuple_impls! {
1 TupleVisitor1 => (0 T0) 1 => (0 T0)
2 TupleVisitor2 => (0 T0 1 T1) 2 => (0 T0 1 T1)
3 TupleVisitor3 => (0 T0 1 T1 2 T2) 3 => (0 T0 1 T1 2 T2)
4 TupleVisitor4 => (0 T0 1 T1 2 T2 3 T3) 4 => (0 T0 1 T1 2 T2 3 T3)
5 TupleVisitor5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
6 TupleVisitor6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
7 TupleVisitor7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
8 TupleVisitor8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
9 TupleVisitor9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
10 TupleVisitor10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
11 TupleVisitor11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
12 TupleVisitor12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
13 TupleVisitor13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
14 TupleVisitor14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
15 TupleVisitor15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
16 TupleVisitor16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1068,7 +1271,12 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new); parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
#[cfg(feature = "std")] #[cfg(feature = "std")]
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0)); parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
ip,
port,
0,
0
));
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1179,7 +1387,9 @@ impl<'de> Visitor<'de> for OsStringVisitor {
match try!(data.variant()) { match try!(data.variant()) {
(OsStringKind::Unix, v) => v.newtype_variant().map(OsString::from_vec), (OsStringKind::Unix, v) => v.newtype_variant().map(OsString::from_vec),
(OsStringKind::Windows, _) => Err(Error::custom("cannot deserialize Windows OS string on Unix",),), (OsStringKind::Windows, _) => Err(Error::custom(
"cannot deserialize Windows OS string on Unix",
)),
} }
} }
@@ -1191,11 +1401,11 @@ impl<'de> Visitor<'de> for OsStringVisitor {
use std::os::windows::ffi::OsStringExt; use std::os::windows::ffi::OsStringExt;
match try!(data.variant()) { match try!(data.variant()) {
(OsStringKind::Windows, v) => { (OsStringKind::Windows, v) => v.newtype_variant::<Vec<u16>>()
v.newtype_variant::<Vec<u16>>() .map(|vec| OsString::from_wide(&vec)),
.map(|vec| OsString::from_wide(&vec)) (OsStringKind::Unix, _) => Err(Error::custom(
} "cannot deserialize Unix OS string on Windows",
(OsStringKind::Unix, _) => Err(Error::custom("cannot deserialize Unix OS string on Windows",),), )),
} }
} }
} }
@@ -1521,13 +1731,17 @@ impl<'de> Deserialize<'de> for SystemTime {
match key { match key {
Field::Secs => { Field::Secs => {
if secs.is_some() { if secs.is_some() {
return Err(<A::Error as Error>::duplicate_field("secs_since_epoch")); return Err(<A::Error as Error>::duplicate_field(
"secs_since_epoch",
));
} }
secs = Some(try!(map.next_value())); secs = Some(try!(map.next_value()));
} }
Field::Nanos => { Field::Nanos => {
if nanos.is_some() { if nanos.is_some() {
return Err(<A::Error as Error>::duplicate_field("nanos_since_epoch")); return Err(<A::Error as Error>::duplicate_field(
"nanos_since_epoch",
));
} }
nanos = Some(try!(map.next_value())); nanos = Some(try!(map.next_value()));
} }
@@ -1691,7 +1905,13 @@ where
} }
const FIELDS: &'static [&'static str] = &["start", "end"]; const FIELDS: &'static [&'static str] = &["start", "end"];
deserializer.deserialize_struct("Range", FIELDS, RangeVisitor { phantom: PhantomData }) deserializer.deserialize_struct(
"Range",
FIELDS,
RangeVisitor {
phantom: PhantomData,
},
)
} }
} }
@@ -1756,9 +1976,10 @@ where
match value { match value {
0 => Ok(Field::Ok), 0 => Ok(Field::Ok),
1 => Ok(Field::Err), 1 => Ok(Field::Err),
_ => { _ => Err(Error::invalid_value(
Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),) Unexpected::Unsigned(value as u64),
} &self,
)),
} }
} }
@@ -1780,14 +2001,12 @@ where
match value { match value {
b"Ok" => Ok(Field::Ok), b"Ok" => Ok(Field::Ok),
b"Err" => Ok(Field::Err), b"Err" => Ok(Field::Err),
_ => { _ => match str::from_utf8(value) {
match str::from_utf8(value) { Ok(value) => Err(Error::unknown_variant(value, VARIANTS)),
Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), Err(_) => {
Err(_) => { Err(Error::invalid_value(Unexpected::Bytes(value), &self))
Err(Error::invalid_value(Unexpected::Bytes(value), &self))
}
} }
} },
} }
} }
} }
@@ -1831,7 +2050,7 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<'de, T> Deserialize<'de> for Wrapping<T> impl<'de, T> Deserialize<'de> for Wrapping<T>
where where
T: Deserialize<'de> T: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error>
where where
+32 -1
View File
@@ -504,6 +504,35 @@ pub trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>; D: Deserializer<'de>;
/// Deserializes a value into `self` from the given Deserializer.
///
/// The purpose of this method is to allow the deserializer to reuse
/// resources and avoid copies. As such, if this method returns an error,
/// `self` will be in an indeterminate state where some parts of the struct
/// have been overwritten. Although whatever state that is will be
/// memory-safe.
///
/// This is generally useful when repeateadly deserializing values that
/// are processed one at a time, where the value of `self` doesn't matter
/// when the next deserialization occurs.
///
/// If you manually implement this, your recursive deserializations should
/// use `deserialize_in_place`.
///
/// This method is stable and an official public API, but hidden from the
/// documentation because it is almost never what newbies are looking for.
/// Showing it in rustdoc would cause it to be featured more prominently
/// than it deserves.
#[doc(hidden)]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
// Default implementation just delegates to `deserialize` impl.
*place = Deserialize::deserialize(deserializer)?;
Ok(())
}
} }
/// A data structure that can be deserialized without borrowing any data from /// A data structure that can be deserialized without borrowing any data from
@@ -1078,7 +1107,9 @@ pub trait Deserializer<'de>: Sized {
/// change, as a value serialized in human-readable mode is not required to /// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode. /// deserialize from the same data in compact mode.
#[inline] #[inline]
fn is_human_readable(&self) -> bool { true } fn is_human_readable(&self) -> bool {
true
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
+34 -14
View File
@@ -37,7 +37,7 @@
use lib::*; use lib::*;
use de::{self, IntoDeserializer, Expected, SeqAccess}; use de::{self, Expected, IntoDeserializer, SeqAccess};
use private::de::size_hint; use private::de::size_hint;
use ser; use ser;
use self::private::{First, Second}; use self::private::{First, Second};
@@ -62,7 +62,9 @@ impl de::Error for Error {
where where
T: Display, T: Display,
{ {
Error { err: msg.to_string().into_boxed_str() } Error {
err: msg.to_string().into_boxed_str(),
}
} }
#[cfg(not(any(feature = "std", feature = "alloc")))] #[cfg(not(any(feature = "std", feature = "alloc")))]
@@ -112,7 +114,9 @@ where
type Deserializer = UnitDeserializer<E>; type Deserializer = UnitDeserializer<E>;
fn into_deserializer(self) -> UnitDeserializer<E> { fn into_deserializer(self) -> UnitDeserializer<E> {
UnitDeserializer { marker: PhantomData } UnitDeserializer {
marker: PhantomData,
}
} }
} }
@@ -658,7 +662,10 @@ where
} else { } else {
// First argument is the number of elements in the data, second // First argument is the number of elements in the data, second
// argument is the number of elements expected by the Deserialize. // argument is the number of elements expected by the Deserialize.
Err(de::Error::invalid_length(self.count + remaining, &ExpectedInSeq(self.count)),) Err(de::Error::invalid_length(
self.count + remaining,
&ExpectedInSeq(self.count),
))
} }
} }
} }
@@ -852,7 +859,10 @@ where
} else { } else {
// First argument is the number of elements in the data, second // First argument is the number of elements in the data, second
// argument is the number of elements expected by the Deserialize. // argument is the number of elements expected by the Deserialize.
Err(de::Error::invalid_length(self.count + remaining, &ExpectedInMap(self.count)),) Err(de::Error::invalid_length(
self.count + remaining,
&ExpectedInMap(self.count),
))
} }
} }
} }
@@ -901,11 +911,7 @@ where
Ok(value) Ok(value)
} }
fn deserialize_tuple<V>( fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
self,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: de::Visitor<'de>, V: de::Visitor<'de>,
{ {
@@ -1223,7 +1229,12 @@ mod private {
} }
pub fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) { pub fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) {
(t, UnitOnly { marker: PhantomData }) (
t,
UnitOnly {
marker: PhantomData,
},
)
} }
impl<'de, E> de::VariantAccess<'de> for UnitOnly<E> impl<'de, E> de::VariantAccess<'de> for UnitOnly<E>
@@ -1240,14 +1251,20 @@ mod private {
where where
T: de::DeserializeSeed<'de>, T: de::DeserializeSeed<'de>,
{ {
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"newtype variant"),) Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"newtype variant",
))
} }
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
where where
V: de::Visitor<'de>, V: de::Visitor<'de>,
{ {
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"tuple variant"),) Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"tuple variant",
))
} }
fn struct_variant<V>( fn struct_variant<V>(
@@ -1258,7 +1275,10 @@ mod private {
where where
V: de::Visitor<'de>, V: de::Visitor<'de>,
{ {
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"struct variant"),) Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"struct variant",
))
} }
} }
+1 -1
View File
@@ -12,7 +12,7 @@ pub use lib::default::Default;
pub use lib::fmt::{self, Formatter}; pub use lib::fmt::{self, Formatter};
pub use lib::marker::PhantomData; pub use lib::marker::PhantomData;
pub use lib::option::Option::{self, None, Some}; pub use lib::option::Option::{self, None, Some};
pub use lib::result::Result::{self, Ok, Err}; pub use lib::result::Result::{self, Err, Ok};
pub use self::string::from_utf8_lossy; pub use self::string::from_utf8_lossy;
+11 -19
View File
@@ -79,28 +79,21 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// 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.25")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue: // discussion of these features please refer to this issue:
// //
// https://github.com/serde-rs/serde/issues/812 // https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))] #![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow( #![cfg_attr(feature = "cargo-clippy",
cast_lossless, allow(cast_lossless, const_static_lifetime, doc_markdown, linkedlist,
doc_markdown, needless_pass_by_value, type_complexity, unreadable_literal,
linkedlist, zero_prefixed_literal))]
type_complexity,
unreadable_literal,
zero_prefixed_literal,
))]
// Whitelisted clippy_pedantic lints // Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow( #![cfg_attr(feature = "cargo-clippy", allow(
// integer and float ser/de requires these sorts of casts // integer and float ser/de requires these sorts of casts
@@ -123,7 +116,6 @@
empty_enum, empty_enum,
use_debug, use_debug,
))] ))]
// Blacklisted Rust lints. // Blacklisted Rust lints.
#![deny(missing_docs, unused_imports)] #![deny(missing_docs, unused_imports)]
@@ -147,8 +139,8 @@ mod lib {
} }
pub use self::core::{cmp, iter, mem, ops, slice, str}; pub use self::core::{cmp, iter, mem, ops, slice, str};
pub use self::core::{i8, i16, i32, i64, isize}; pub use self::core::{isize, i16, i32, i64, i8};
pub use self::core::{u8, u16, u32, u64, usize}; pub use self::core::{usize, u16, u32, u64, u8};
pub use self::core::{f32, f64}; pub use self::core::{f32, f64};
pub use self::core::cell::{Cell, RefCell}; pub use self::core::cell::{Cell, RefCell};
@@ -191,9 +183,9 @@ mod lib {
pub use alloc::arc::Arc; pub use alloc::arc::Arc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque}; pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque}; pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::{error, net}; pub use std::{error, net};
@@ -201,9 +193,9 @@ mod lib {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::collections::{HashMap, HashSet}; pub use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::ffi::{CString, CStr, OsString, OsStr}; pub use std::ffi::{CStr, CString, OsStr, OsString};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::hash::{Hash, BuildHasher}; pub use std::hash::{BuildHasher, Hash};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::io::Write; pub use std::io::Write;
#[cfg(feature = "std")] #[cfg(feature = "std")]
+191 -103
View File
@@ -8,16 +8,16 @@
use lib::*; use lib::*;
use de::{Deserialize, Deserializer, IntoDeserializer, Error, Visitor}; use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use de::Unexpected; use de::Unexpected;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentRefDeserializer, ContentDeserializer, pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer,
TaggedContentVisitor, TagOrContentField, TagOrContentFieldVisitor, InternallyTaggedUnitVisitor, TagContentOtherField,
TagContentOtherField, TagContentOtherFieldVisitor, TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
InternallyTaggedUnitVisitor, UntaggedUnitVisitor}; TaggedContentVisitor, UntaggedUnitVisitor};
/// If the missing field is of type `Option<T>` then treat is as `None`, /// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error. /// otherwise it is an error.
@@ -120,7 +120,10 @@ where
{ {
match String::from_utf8(v) { match String::from_utf8(v) {
Ok(s) => Ok(Cow::Owned(s)), Ok(s) => Ok(Cow::Owned(s)),
Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self),), Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
} }
} }
} }
@@ -198,6 +201,7 @@ pub mod size_hint {
helper(iter.size_hint()) helper(iter.size_hint())
} }
#[inline]
pub fn cautious(hint: Option<usize>) -> usize { pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096) cmp::min(hint.unwrap_or(0), 4096)
} }
@@ -224,8 +228,8 @@ mod content {
use lib::*; use lib::*;
use de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess, MapAccess, use de::{self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, MapAccess, SeqAccess,
EnumAccess, Unexpected}; Unexpected, Visitor};
use super::size_hint; use super::size_hint;
/// Used from generated code to buffer the contents of the Deserializer when /// Used from generated code to buffer the contents of the Deserializer when
@@ -501,7 +505,9 @@ mod content {
where where
V: EnumAccess<'de>, V: EnumAccess<'de>,
{ {
Err(de::Error::custom("untagged and internally tagged enums do not support enum input",),) Err(de::Error::custom(
"untagged and internally tagged enums do not support enum input",
))
} }
} }
@@ -520,7 +526,10 @@ mod content {
impl<'de> TagOrContentVisitor<'de> { impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self { fn new(name: &'static str) -> Self {
TagOrContentVisitor { name: name, value: PhantomData } TagOrContentVisitor {
name: name,
value: PhantomData,
}
} }
} }
@@ -557,7 +566,9 @@ mod content {
where where
F: de::Error, F: de::Error,
{ {
ContentVisitor::new().visit_i8(value).map(TagOrContent::Content) ContentVisitor::new()
.visit_i8(value)
.map(TagOrContent::Content)
} }
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F> fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
@@ -591,7 +602,9 @@ mod content {
where where
F: de::Error, F: de::Error,
{ {
ContentVisitor::new().visit_u8(value).map(TagOrContent::Content) ContentVisitor::new()
.visit_u8(value)
.map(TagOrContent::Content)
} }
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F> fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
@@ -730,14 +743,18 @@ mod content {
where where
F: de::Error, F: de::Error,
{ {
ContentVisitor::new().visit_unit().map(TagOrContent::Content) ContentVisitor::new()
.visit_unit()
.map(TagOrContent::Content)
} }
fn visit_none<F>(self) -> Result<Self::Value, F> fn visit_none<F>(self) -> Result<Self::Value, F>
where where
F: de::Error, F: de::Error,
{ {
ContentVisitor::new().visit_none().map(TagOrContent::Content) ContentVisitor::new()
.visit_none()
.map(TagOrContent::Content)
} }
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
@@ -860,8 +877,7 @@ mod content {
{ {
let mut tag = None; let mut tag = None;
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint())); let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
while let Some(k) = while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k { match k {
TagOrContent::Tag => { TagOrContent::Tag => {
if tag.is_some() { if tag.is_some() {
@@ -877,14 +893,10 @@ mod content {
} }
match tag { match tag {
None => Err(de::Error::missing_field(self.tag_name)), None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => { Some(tag) => Ok(TaggedContent {
Ok( tag: tag,
TaggedContent { content: Content::Map(vec),
tag: tag, }),
content: Content::Map(vec),
},
)
}
} }
} }
} }
@@ -966,7 +978,11 @@ mod content {
type Value = TagContentOtherField; type Value = TagContentOtherField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}, {:?}, or other ignored fields", self.tag, self.content) write!(
formatter,
"{:?}, {:?}, or other ignored fields",
self.tag, self.content
)
} }
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E> fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
@@ -1030,10 +1046,8 @@ mod content {
Ok(value) Ok(value)
} }
Content::Map(v) => { Content::Map(v) => {
let map = v.into_iter().map(|(k, v)| { let map = v.into_iter()
(ContentDeserializer::new(k), .map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v)));
ContentDeserializer::new(v))
});
let mut map_visitor = de::value::MapDeserializer::new(map); let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor)); let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end()); try!(map_visitor.end());
@@ -1080,44 +1094,69 @@ mod content {
let (variant, value) = match iter.next() { let (variant, value) = match iter.next() {
Some(v) => v, Some(v) => v,
None => { None => {
return Err( return Err(de::Error::invalid_value(
de::Error::invalid_value( de::Unexpected::Map,
de::Unexpected::Map, &"map with a single key",
&"map with a single key", ));
),
);
} }
}; };
// enums are encoded in json as maps with a single key:value pair // enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() { if iter.next().is_some() {
return Err( return Err(de::Error::invalid_value(
de::Error::invalid_value( de::Unexpected::Map,
de::Unexpected::Map, &"map with a single key",
&"map with a single key", ));
),
);
} }
(variant, Some(value)) (variant, Some(value))
} }
s @ Content::String(_) | s @ Content::Str(_) => (s, None), s @ Content::String(_) | s @ Content::Str(_) => (s, None),
other => { other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),); return Err(de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
} }
}; };
visitor.visit_enum( visitor.visit_enum(EnumDeserializer {
EnumDeserializer { variant: variant,
variant: variant, value: value,
value: value, err: PhantomData,
err: PhantomData, })
}, }
)
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
} }
} }
@@ -1187,9 +1226,10 @@ mod content {
{ {
match self.value { match self.value {
Some(value) => seed.deserialize(ContentDeserializer::new(value)), Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => { None => Err(de::Error::invalid_type(
Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant"),) de::Unexpected::UnitVariant,
} &"newtype variant",
)),
} }
} }
@@ -1201,8 +1241,14 @@ mod content {
Some(Content::Seq(v)) => { Some(Content::Seq(v)) => {
de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
} }
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant"),), Some(other) => Err(de::Error::invalid_type(
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"),), other.unexpected(),
&"tuple variant",
)),
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"tuple variant",
)),
} }
} }
@@ -1218,8 +1264,17 @@ mod content {
Some(Content::Map(v)) => { Some(Content::Map(v)) => {
de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
} }
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant"),), Some(Content::Seq(v)) => {
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"),), de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"struct variant",
)),
_ => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"struct variant",
)),
} }
} }
} }
@@ -1287,10 +1342,7 @@ mod content {
T: de::DeserializeSeed<'de>, T: de::DeserializeSeed<'de>,
{ {
match self.iter.next() { match self.iter.next() {
Some(value) => { Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some),
seed.deserialize(ContentDeserializer::new(value))
.map(Some)
}
None => Ok(None), None => Ok(None),
} }
} }
@@ -1426,12 +1478,12 @@ mod content {
Ok(value) Ok(value)
} }
Content::Map(ref v) => { Content::Map(ref v) => {
let map = v.into_iter() let map = v.into_iter().map(|&(ref k, ref v)| {
.map( (
|&(ref k, ref v)| { ContentRefDeserializer::new(k),
(ContentRefDeserializer::new(k), ContentRefDeserializer::new(v)) ContentRefDeserializer::new(v),
}, )
); });
let mut map_visitor = de::value::MapDeserializer::new(map); let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor)); let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end()); try!(map_visitor.end());
@@ -1474,38 +1526,35 @@ mod content {
let &(ref variant, ref value) = match iter.next() { let &(ref variant, ref value) = match iter.next() {
Some(v) => v, Some(v) => v,
None => { None => {
return Err( return Err(de::Error::invalid_value(
de::Error::invalid_value( de::Unexpected::Map,
de::Unexpected::Map, &"map with a single key",
&"map with a single key", ));
),
);
} }
}; };
// enums are encoded in json as maps with a single key:value pair // enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() { if iter.next().is_some() {
return Err( return Err(de::Error::invalid_value(
de::Error::invalid_value( de::Unexpected::Map,
de::Unexpected::Map, &"map with a single key",
&"map with a single key", ));
),
);
} }
(variant, Some(value)) (variant, Some(value))
} }
ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None), ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None),
ref other => { ref other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),); return Err(de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
} }
}; };
visitor.visit_enum( visitor.visit_enum(EnumRefDeserializer {
EnumRefDeserializer { variant: variant,
variant: variant, value: value,
value: value, err: PhantomData,
err: PhantomData, })
},
)
} }
forward_to_deserialize_any! { forward_to_deserialize_any! {
@@ -1581,9 +1630,10 @@ mod content {
{ {
match self.value { match self.value {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => { None => Err(de::Error::invalid_type(
Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant"),) de::Unexpected::UnitVariant,
} &"newtype variant",
)),
} }
} }
@@ -1595,8 +1645,14 @@ mod content {
Some(&Content::Seq(ref v)) => { Some(&Content::Seq(ref v)) => {
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
} }
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant"),), Some(other) => Err(de::Error::invalid_type(
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"),), other.unexpected(),
&"tuple variant",
)),
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"tuple variant",
)),
} }
} }
@@ -1612,8 +1668,17 @@ mod content {
Some(&Content::Map(ref v)) => { Some(&Content::Map(ref v)) => {
de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor) de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
} }
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant"),), Some(&Content::Seq(ref v)) => {
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"),), de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"struct variant",
)),
_ => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"struct variant",
)),
} }
} }
} }
@@ -1681,10 +1746,8 @@ mod content {
T: de::DeserializeSeed<'de>, T: de::DeserializeSeed<'de>,
{ {
match self.iter.next() { match self.iter.next() {
Some(value) => { Some(value) => seed.deserialize(ContentRefDeserializer::new(value))
seed.deserialize(ContentRefDeserializer::new(value)) .map(Some),
.map(Some)
}
None => Ok(None), None => Ok(None),
} }
} }
@@ -1729,8 +1792,7 @@ mod content {
match self.iter.next() { match self.iter.next() {
Some(&(ref key, ref value)) => { Some(&(ref key, ref value)) => {
self.value = Some(value); self.value = Some(value);
seed.deserialize(ContentRefDeserializer::new(key)) seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
.map(Some)
} }
None => Ok(None), None => Ok(None),
} }
@@ -1816,7 +1878,11 @@ mod content {
type Value = (); type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name) write!(
formatter,
"unit variant {}::{}",
self.type_name, self.variant_name
)
} }
fn visit_seq<S>(self, _: S) -> Result<(), S::Error> fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
@@ -1856,7 +1922,11 @@ mod content {
type Value = (); type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name) write!(
formatter,
"unit variant {}::{}",
self.type_name, self.variant_name
)
} }
fn visit_unit<E>(self) -> Result<(), E> fn visit_unit<E>(self) -> Result<(), E>
@@ -1974,3 +2044,21 @@ where
map struct enum identifier ignored_any map struct enum identifier ignored_any
} }
} }
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
///
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
where
T: Deserialize<'de>,
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_in_place(deserializer, self.0)
}
}
+98 -87
View File
@@ -8,10 +8,10 @@
use lib::*; use lib::*;
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible}; use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue}; use self::content::{SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue};
/// Used to check that serde(getter) attributes return the expected type. /// Used to check that serde(getter) attributes return the expected type.
/// Not public API. /// Not public API.
@@ -32,15 +32,13 @@ where
S: Serializer, S: Serializer,
T: Serialize, T: Serialize,
{ {
value.serialize( value.serialize(TaggedSerializer {
TaggedSerializer { type_ident: type_ident,
type_ident: type_ident, variant_ident: variant_ident,
variant_ident: variant_ident, tag: tag,
tag: tag, variant_name: variant_name,
variant_name: variant_name, delegate: serializer,
delegate: serializer, })
},
)
} }
struct TaggedSerializer<S> { struct TaggedSerializer<S> {
@@ -60,7 +58,6 @@ enum Unsupported {
ByteArray, ByteArray,
Optional, Optional,
Unit, Unit,
UnitStruct,
Sequence, Sequence,
Tuple, Tuple,
TupleStruct, TupleStruct,
@@ -79,7 +76,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"),
@@ -94,13 +90,10 @@ where
S: Serializer, S: Serializer,
{ {
fn bad_type(self, what: Unsupported) -> S::Error { fn bad_type(self, what: Unsupported) -> S::Error {
ser::Error::custom( ser::Error::custom(format_args!(
format_args!(
"cannot serialize tagged newtype variant {}::{} containing {}", "cannot serialize tagged newtype variant {}::{} containing {}",
self.type_ident, self.type_ident, self.variant_ident, what
self.variant_ident, ))
what),
)
} }
} }
@@ -199,7 +192,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(
@@ -281,7 +276,11 @@ where
let mut map = try!(self.delegate.serialize_map(Some(2))); let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name)); try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant)); try!(map.serialize_key(inner_variant));
Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len),) Ok(SerializeTupleVariantAsMapValue::new(
map,
inner_variant,
len,
))
} }
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
@@ -324,7 +323,11 @@ where
let mut map = try!(self.delegate.serialize_map(Some(2))); let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name)); try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant)); try!(map.serialize_key(inner_variant));
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len),) Ok(SerializeStructVariantAsMapValue::new(
map,
inner_variant,
len,
))
} }
#[cfg(not(any(feature = "std", feature = "alloc")))] #[cfg(not(any(feature = "std", feature = "alloc")))]
@@ -402,7 +405,10 @@ mod content {
} }
fn end(mut self) -> Result<M::Ok, M::Error> { fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::TupleStruct(self.name, self.fields))); try!(
self.map
.serialize_value(&Content::TupleStruct(self.name, self.fields))
);
self.map.end() self.map.end()
} }
} }
@@ -444,7 +450,10 @@ mod content {
} }
fn end(mut self) -> Result<M::Ok, M::Error> { fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields))); try!(
self.map
.serialize_value(&Content::Struct(self.name, self.fields))
);
self.map.end() self.map.end()
} }
} }
@@ -485,7 +494,12 @@ mod content {
TupleVariant(&'static str, u32, &'static str, Vec<Content>), TupleVariant(&'static str, u32, &'static str, Vec<Content>),
Map(Vec<(Content, Content)>), Map(Vec<(Content, Content)>),
Struct(&'static str, Vec<(&'static str, Content)>), Struct(&'static str, Vec<(&'static str, Content)>),
StructVariant(&'static str, u32, &'static str, Vec<(&'static str, Content)>), StructVariant(
&'static str,
u32,
&'static str,
Vec<(&'static str, Content)>,
),
} }
impl Serialize for Content { impl Serialize for Content {
@@ -687,7 +701,10 @@ mod content {
where where
T: Serialize, T: Serialize,
{ {
Ok(Content::NewtypeStruct(name, Box::new(try!(value.serialize(self)))),) Ok(Content::NewtypeStruct(
name,
Box::new(try!(value.serialize(self))),
))
} }
fn serialize_newtype_variant<T: ?Sized>( fn serialize_newtype_variant<T: ?Sized>(
@@ -700,32 +717,26 @@ mod content {
where where
T: Serialize, T: Serialize,
{ {
Ok( Ok(Content::NewtypeVariant(
Content::NewtypeVariant( name,
name, variant_index,
variant_index, variant,
variant, Box::new(try!(value.serialize(self))),
Box::new(try!(value.serialize(self))), ))
),
)
} }
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, E> { fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, E> {
Ok( Ok(SerializeSeq {
SerializeSeq { elements: Vec::with_capacity(len.unwrap_or(0)),
elements: Vec::with_capacity(len.unwrap_or(0)), error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, E> { fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, E> {
Ok( Ok(SerializeTuple {
SerializeTuple { elements: Vec::with_capacity(len),
elements: Vec::with_capacity(len), error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_tuple_struct( fn serialize_tuple_struct(
@@ -733,13 +744,11 @@ mod content {
name: &'static str, name: &'static str,
len: usize, len: usize,
) -> Result<Self::SerializeTupleStruct, E> { ) -> Result<Self::SerializeTupleStruct, E> {
Ok( Ok(SerializeTupleStruct {
SerializeTupleStruct { name: name,
name: name, fields: Vec::with_capacity(len),
fields: Vec::with_capacity(len), error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_tuple_variant( fn serialize_tuple_variant(
@@ -749,25 +758,21 @@ mod content {
variant: &'static str, variant: &'static str,
len: usize, len: usize,
) -> Result<Self::SerializeTupleVariant, E> { ) -> Result<Self::SerializeTupleVariant, E> {
Ok( Ok(SerializeTupleVariant {
SerializeTupleVariant { name: name,
name: name, variant_index: variant_index,
variant_index: variant_index, variant: variant,
variant: variant, fields: Vec::with_capacity(len),
fields: Vec::with_capacity(len), error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, E> { fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, E> {
Ok( Ok(SerializeMap {
SerializeMap { entries: Vec::with_capacity(len.unwrap_or(0)),
entries: Vec::with_capacity(len.unwrap_or(0)), key: None,
key: None, error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_struct( fn serialize_struct(
@@ -775,13 +780,11 @@ mod content {
name: &'static str, name: &'static str,
len: usize, len: usize,
) -> Result<Self::SerializeStruct, E> { ) -> Result<Self::SerializeStruct, E> {
Ok( Ok(SerializeStruct {
SerializeStruct { name: name,
name: name, fields: Vec::with_capacity(len),
fields: Vec::with_capacity(len), error: PhantomData,
error: PhantomData, })
},
)
} }
fn serialize_struct_variant( fn serialize_struct_variant(
@@ -791,15 +794,13 @@ mod content {
variant: &'static str, variant: &'static str,
len: usize, len: usize,
) -> Result<Self::SerializeStructVariant, E> { ) -> Result<Self::SerializeStructVariant, E> {
Ok( Ok(SerializeStructVariant {
SerializeStructVariant { name: name,
name: name, variant_index: variant_index,
variant_index: variant_index, variant: variant,
variant: variant, fields: Vec::with_capacity(len),
fields: Vec::with_capacity(len), error: PhantomData,
error: PhantomData, })
},
)
} }
} }
@@ -907,7 +908,12 @@ mod content {
} }
fn end(self) -> Result<Content, E> { fn end(self) -> Result<Content, E> {
Ok(Content::TupleVariant(self.name, self.variant_index, self.variant, self.fields),) Ok(Content::TupleVariant(
self.name,
self.variant_index,
self.variant,
self.fields,
))
} }
} }
@@ -1013,7 +1019,12 @@ mod content {
} }
fn end(self) -> Result<Content, E> { fn end(self) -> Result<Content, E> {
Ok(Content::StructVariant(self.name, self.variant_index, self.variant, self.fields),) Ok(Content::StructVariant(
self.name,
self.variant_index,
self.variant,
self.fields,
))
} }
} }
} }
+18 -10
View File
@@ -464,7 +464,8 @@ impl Serialize for SystemTime {
S: Serializer, S: Serializer,
{ {
use super::SerializeStruct; use super::SerializeStruct;
let duration_since_epoch = self.duration_since(UNIX_EPOCH).expect("SystemTime must be later than UNIX_EPOCH"); let duration_since_epoch = self.duration_since(UNIX_EPOCH)
.expect("SystemTime must be later than UNIX_EPOCH");
let mut state = try!(serializer.serialize_struct("SystemTime", 2)); let mut state = try!(serializer.serialize_struct("SystemTime", 2));
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs())); try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos())); try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
@@ -513,10 +514,12 @@ impl Serialize for net::IpAddr {
} }
} else { } else {
match *self { match *self {
net::IpAddr::V4(ref a) => net::IpAddr::V4(ref a) => {
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a), serializer.serialize_newtype_variant("IpAddr", 0, "V4", a)
net::IpAddr::V6(ref a) => }
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a), net::IpAddr::V6(ref a) => {
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a)
}
} }
} }
} }
@@ -567,10 +570,12 @@ impl Serialize for net::SocketAddr {
} }
} else { } else {
match *self { match *self {
net::SocketAddr::V4(ref addr) => net::SocketAddr::V4(ref addr) => {
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr), serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr)
net::SocketAddr::V6(ref addr) => }
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr), net::SocketAddr::V6(ref addr) => {
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr)
}
} }
} }
} }
@@ -600,7 +605,10 @@ impl Serialize for net::SocketAddrV6 {
{ {
if serializer.is_human_readable() { if serializer.is_human_readable() {
const MAX_LEN: usize = 47; const MAX_LEN: usize = 47;
debug_assert_eq!(MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len()); debug_assert_eq!(
MAX_LEN,
"[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len()
);
serialize_display_bounded_length!(self, MAX_LEN, serializer) serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else { } else {
(self.ip(), self.port()).serialize(serializer) (self.ip(), self.port()).serialize(serializer)
+2 -2
View File
@@ -10,8 +10,8 @@
use lib::*; use lib::*;
use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant}; SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
/// Helper type for implementing a `Serializer` that does not support /// Helper type for implementing a `Serializer` that does not support
/// serializing one of the compound types. /// serializing one of the compound types.
+3 -1
View File
@@ -1412,7 +1412,9 @@ pub trait Serializer: Sized {
/// change, as a value serialized in human-readable mode is not required to /// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode. /// deserialize from the same data in compact mode.
#[inline] #[inline]
fn is_human_readable(&self) -> bool { true } fn is_human_readable(&self) -> bool {
true
}
} }
/// Returned from `Serializer::serialize_seq`. /// Returned from `Serializer::serialize_seq`.
+6 -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.25" # 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)]"
@@ -14,13 +14,17 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
[features]
default = []
deserialize_in_place = []
[lib] [lib]
name = "serde_derive" name = "serde_derive"
proc-macro = true 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.18.1", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] } syn = { version = "0.11", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
+59 -67
View File
@@ -27,14 +27,10 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
ty_params: generics ty_params: generics
.ty_params .ty_params
.iter() .iter()
.map( .map(|ty_param| syn::TyParam {
|ty_param| { default: None,
syn::TyParam { ..ty_param.clone()
default: None, })
..ty_param.clone()
}
},
)
.collect(), .collect(),
..generics.clone() ..generics.clone()
} }
@@ -116,6 +112,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
@@ -129,17 +133,15 @@ where
relevant_ty_params: HashSet::new(), relevant_ty_params: HashSet::new(),
}; };
match cont.body { match cont.body {
Body::Enum(ref variants) => { Body::Enum(ref variants) => for variant in variants.iter() {
for variant in variants.iter() { let relevant_fields = variant
let relevant_fields = variant .fields
.fields .iter()
.iter() .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
.filter(|field| filter(&field.attrs, Some(&variant.attrs))); for field in relevant_fields {
for field in relevant_fields { visit::walk_ty(&mut visitor, field.ty);
visit::walk_ty(&mut visitor, field.ty);
}
} }
} },
Body::Struct(_, ref fields) => { Body::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) { for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visit::walk_ty(&mut visitor, field.ty); visit::walk_ty(&mut visitor, field.ty);
@@ -152,27 +154,23 @@ where
.iter() .iter()
.map(|ty_param| ty_param.ident.clone()) .map(|ty_param| ty_param.ident.clone())
.filter(|id| visitor.relevant_ty_params.contains(id)) .filter(|id| visitor.relevant_ty_params.contains(id))
.map( .map(|id| {
|id| { syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
syn::WherePredicate::BoundPredicate( bound_lifetimes: Vec::new(),
syn::WhereBoundPredicate { // the type parameter that is being bounded e.g. T
bound_lifetimes: Vec::new(), bounded_ty: syn::Ty::Path(None, id.into()),
// the type parameter that is being bounded e.g. T // the bound e.g. Serialize
bounded_ty: syn::Ty::Path(None, id.into()), bounds: vec![
// the bound e.g. Serialize syn::TyParamBound::Trait(
bounds: vec![ syn::PolyTraitRef {
syn::TyParamBound::Trait( bound_lifetimes: Vec::new(),
syn::PolyTraitRef { trait_ref: bound.clone(),
bound_lifetimes: Vec::new(), },
trait_ref: bound.clone(), syn::TraitBoundModifier::None,
}, ),
syn::TraitBoundModifier::None, ],
), })
], });
},
)
},
);
let mut generics = generics.clone(); let mut generics = generics.clone();
generics.where_clause.predicates.extend(new_predicates); generics.where_clause.predicates.extend(new_predicates);
@@ -188,25 +186,23 @@ pub fn with_self_bound(
generics generics
.where_clause .where_clause
.predicates .predicates
.push( .push(syn::WherePredicate::BoundPredicate(
syn::WherePredicate::BoundPredicate( syn::WhereBoundPredicate {
syn::WhereBoundPredicate { bound_lifetimes: Vec::new(),
bound_lifetimes: Vec::new(), // the type that is being bounded e.g. MyStruct<'a, T>
// the type that is being bounded e.g. MyStruct<'a, T> bounded_ty: type_of_item(cont),
bounded_ty: type_of_item(cont), // the bound e.g. Default
// the bound e.g. Default bounds: vec![
bounds: vec![ syn::TyParamBound::Trait(
syn::TyParamBound::Trait( syn::PolyTraitRef {
syn::PolyTraitRef { bound_lifetimes: Vec::new(),
bound_lifetimes: Vec::new(), trait_ref: bound.clone(),
trait_ref: bound.clone(), },
}, syn::TraitBoundModifier::None,
syn::TraitBoundModifier::None, ),
), ],
], },
}, ));
),
);
generics generics
} }
@@ -223,15 +219,11 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime))); .push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
} }
generics generics.lifetimes.push(syn::LifetimeDef {
.lifetimes attrs: Vec::new(),
.push( lifetime: syn::Lifetime::new(lifetime),
syn::LifetimeDef { bounds: Vec::new(),
attrs: Vec::new(), });
lifetime: syn::Lifetime::new(lifetime),
bounds: Vec::new(),
},
);
generics generics
} }
+870 -303
View File
File diff suppressed because it is too large Load Diff
+10 -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.
use quote::{Tokens, ToTokens}; use quote::{ToTokens, Tokens};
pub enum Fragment { pub enum Fragment {
/// Tokens that can be used as an expression. /// Tokens that can be used as an expression.
@@ -73,3 +73,12 @@ impl ToTokens for Match {
} }
} }
} }
impl AsRef<Tokens> for Fragment {
fn as_ref(&self) -> &Tokens {
match *self {
Fragment::Expr(ref expr) => expr,
Fragment::Block(ref block) => block,
}
}
}
+2 -4
View File
@@ -22,17 +22,15 @@
//! //!
//! [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.25")]
#![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))]
// The `quote!` macro requires deep recursion. // The `quote!` macro requires deep recursion.
#![recursion_limit = "192"] #![recursion_limit = "192"]
extern crate syn;
#[macro_use] #[macro_use]
extern crate quote; extern crate quote;
extern crate syn;
extern crate serde_derive_internals as internals; extern crate serde_derive_internals as internals;
+191 -231
View File
@@ -10,7 +10,7 @@ use syn::{self, Ident};
use quote::Tokens; use quote::Tokens;
use bound; use bound;
use fragment::{Fragment, Stmts, Match}; use fragment::{Fragment, Match, Stmts};
use internals::ast::{Body, Container, Field, Style, Variant}; use internals::ast::{Body, Container, Field, Style, Variant};
use internals::{attr, Ctxt}; use internals::{attr, Ctxt};
@@ -132,14 +132,12 @@ fn build_generics(cont: &Container) -> syn::Generics {
match cont.attrs.ser_bound() { match cont.attrs.ser_bound() {
Some(predicates) => bound::with_where_predicates(&generics, predicates), Some(predicates) => bound::with_where_predicates(&generics, predicates),
None => { None => bound::with_bound(
bound::with_bound( cont,
cont, &generics,
&generics, needs_serialize_bound,
needs_serialize_bound, &path!(_serde::Serialize),
&path!(_serde::Serialize), ),
)
}
} }
} }
@@ -149,10 +147,8 @@ fn build_generics(cont: &Container) -> syn::Generics {
// their own bound so we do not generate one. All other fields may need a `T: // their own bound so we do not generate one. All other fields may need a `T:
// Serialize` bound where T is the type of the field. // Serialize` bound where T is the type of the field.
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_serializing() && !field.skip_serializing() && field.serialize_with().is_none() && field.ser_bound().is_none()
field.serialize_with().is_none() && && variant.map_or(true, |variant| variant.serialize_with().is_none())
field.ser_bound().is_none() &&
variant.map_or(true, |variant| variant.serialize_with().is_none())
} }
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
@@ -259,16 +255,14 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
let let_mut = mut_if(serialized_fields.peek().is_some()); let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields let len = serialized_fields
.map( .map(|field| match field.attrs.skip_serializing_if() {
|field| match field.attrs.skip_serializing_if() { None => quote!(1),
None => quote!(1), Some(path) => {
Some(path) => { let ident = field.ident.clone().expect("struct has unnamed fields");
let ident = field.ident.clone().expect("struct has unnamed fields"); let field_expr = get_field(params, field, ident);
let field_expr = get_field(params, field, ident); quote!(if #path(#field_expr) { 0 } else { 1 })
quote!(if #path(#field_expr) { 0 } else { 1 }) }
} })
},
)
.fold(quote!(0), |sum, expr| quote!(#sum + #expr)); .fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! { quote_block! {
@@ -286,11 +280,9 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
let arms: Vec<_> = variants let arms: Vec<_> = variants
.iter() .iter()
.enumerate() .enumerate()
.map( .map(|(variant_index, variant)| {
|(variant_index, variant)| { serialize_variant(params, variant, variant_index as u32, cattrs)
serialize_variant(params, variant, variant_index as u32, cattrs) })
},
)
.collect(); .collect();
quote_expr! { quote_expr! {
@@ -321,13 +313,7 @@ fn serialize_variant(
let fields_pat = match variant.style { let fields_pat = match variant.style {
Style::Unit => quote!(), Style::Unit => quote!(),
Style::Newtype | Style::Tuple => quote!((..)), Style::Newtype | Style::Tuple => quote!((..)),
Style::Struct => { Style::Struct => quote!({ .. }),
quote!(
{
..
}
)
}
}; };
quote! { quote! {
#this::#variant_ident #fields_pat => #skipped_err, #this::#variant_ident #fields_pat => #skipped_err,
@@ -356,34 +342,26 @@ fn serialize_variant(
let fields = variant let fields = variant
.fields .fields
.iter() .iter()
.map( .map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
|f| {
f.ident
.clone()
.expect("struct variant has unnamed fields")
},
);
quote! { quote! {
#this::#variant_ident { #(ref #fields),* } #this::#variant_ident { #(ref #fields),* }
} }
} }
}; };
let body = Match( let body = Match(match *cattrs.tag() {
match *cattrs.tag() { attr::EnumTag::External => {
attr::EnumTag::External => { serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
serialize_externally_tagged_variant(params, variant, variant_index, cattrs) }
} attr::EnumTag::Internal { ref tag } => {
attr::EnumTag::Internal { ref tag } => { serialize_internally_tagged_variant(params, variant, cattrs, tag)
serialize_internally_tagged_variant(params, variant, cattrs, tag) }
} attr::EnumTag::Adjacent {
attr::EnumTag::Adjacent { ref tag,
ref tag, ref content,
ref content, } => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content), attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs),
attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs), });
},
);
quote! { quote! {
#case => #body #case => #body
@@ -441,28 +419,24 @@ fn serialize_externally_tagged_variant(
) )
} }
} }
Style::Tuple => { Style::Tuple => serialize_tuple_variant(
serialize_tuple_variant( TupleVariant::ExternallyTagged {
TupleVariant::ExternallyTagged { type_name: type_name,
type_name: type_name, variant_index: variant_index,
variant_index: variant_index, variant_name: variant_name,
variant_name: variant_name, },
}, params,
params, &variant.fields,
&variant.fields, ),
) Style::Struct => serialize_struct_variant(
} StructVariant::ExternallyTagged {
Style::Struct => { variant_index: variant_index,
serialize_struct_variant( variant_name: variant_name,
StructVariant::ExternallyTagged { },
variant_index: variant_index, params,
variant_name: variant_name, &variant.fields,
}, &type_name,
params, ),
&variant.fields,
&type_name,
)
}
} }
} }
@@ -520,17 +494,15 @@ fn serialize_internally_tagged_variant(
) )
} }
} }
Style::Struct => { Style::Struct => serialize_struct_variant(
serialize_struct_variant( StructVariant::InternallyTagged {
StructVariant::InternallyTagged { tag: tag,
tag: tag, variant_name: variant_name,
variant_name: variant_name, },
}, params,
params, &variant.fields,
&variant.fields, &type_name,
&type_name, ),
)
}
Style::Tuple => unreachable!("checked in serde_derive_internals"), Style::Tuple => unreachable!("checked in serde_derive_internals"),
} }
} }
@@ -546,48 +518,44 @@ fn serialize_adjacently_tagged_variant(
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name();
let inner = Stmts( let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
if let Some(path) = variant.attrs.serialize_with() { let ser = wrap_serialize_variant_with(params, path, &variant);
let ser = wrap_serialize_variant_with(params, path, &variant); quote_expr! {
quote_expr! { _serde::Serialize::serialize(#ser, __serializer)
_serde::Serialize::serialize(#ser, __serializer) }
} else {
match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
} }
} else { Style::Newtype => {
match variant.style { let field = &variant.fields[0];
Style::Unit => { let mut field_expr = quote!(__field0);
return quote_block! { if let Some(path) = field.attrs.serialize_with() {
let mut __struct = try!(_serde::Serializer::serialize_struct( field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
} }
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! { quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer) _serde::Serialize::serialize(#field_expr, __serializer)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => {
serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
)
} }
} }
}, Style::Tuple => {
); serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
),
}
});
let fields_ty = variant.fields.iter().map(|f| &f.ty); let fields_ty = variant.fields.iter().map(|f| &f.ty);
let ref fields_ident: Vec<_> = match variant.style { let ref fields_ident: Vec<_> = match variant.style {
@@ -599,24 +567,14 @@ fn serialize_adjacently_tagged_variant(
} }
} }
Style::Newtype => vec![Ident::new("__field0")], Style::Newtype => vec![Ident::new("__field0")],
Style::Tuple => { Style::Tuple => (0..variant.fields.len())
(0..variant.fields.len()) .map(|i| Ident::new(format!("__field{}", i)))
.map(|i| Ident::new(format!("__field{}", i))) .collect(),
.collect() Style::Struct => variant
} .fields
Style::Struct => { .iter()
variant .map(|f| f.ident.clone().expect("struct variant has unnamed fields"))
.fields .collect(),
.iter()
.map(
|f| {
f.ident
.clone()
.expect("struct variant has unnamed fields")
},
)
.collect()
}
}; };
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
@@ -753,7 +711,10 @@ enum StructVariant<'a> {
variant_index: u32, variant_index: u32,
variant_name: String, variant_name: String,
}, },
InternallyTagged { tag: &'a str, variant_name: String }, InternallyTagged {
tag: &'a str,
variant_name: String,
},
Untagged, Untagged,
} }
@@ -764,19 +725,14 @@ fn serialize_struct_variant<'a>(
name: &str, name: &str,
) -> Fragment { ) -> Fragment {
let (method, skip_method) = match context { let (method, skip_method) = match context {
StructVariant::ExternallyTagged { .. } => { StructVariant::ExternallyTagged { .. } => (
( quote!(_serde::ser::SerializeStructVariant::serialize_field),
quote!(_serde::ser::SerializeStructVariant::serialize_field), quote!(_serde::ser::SerializeStructVariant::skip_field),
quote!(_serde::ser::SerializeStructVariant::skip_field), ),
) StructVariant::InternallyTagged { .. } | StructVariant::Untagged => (
} quote!(_serde::ser::SerializeStruct::serialize_field),
StructVariant::InternallyTagged { .. } | quote!(_serde::ser::SerializeStruct::skip_field),
StructVariant::Untagged => { ),
(
quote!(_serde::ser::SerializeStruct::serialize_field),
quote!(_serde::ser::SerializeStruct::skip_field),
)
}
}; };
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method); let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
@@ -789,16 +745,14 @@ fn serialize_struct_variant<'a>(
let let_mut = mut_if(serialized_fields.peek().is_some()); let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields let len = serialized_fields
.map( .map(|field| {
|field| { let ident = field.ident.clone().expect("struct has unnamed fields");
let ident = field.ident.clone().expect("struct has unnamed fields");
match field.attrs.skip_serializing_if() { match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }), Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
None => quote!(1), None => quote!(1),
} }
}, })
)
.fold(quote!(0), |sum, expr| quote!(#sum + #expr)); .fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context { match context {
@@ -857,34 +811,32 @@ fn serialize_tuple_struct_visitor(
fields fields
.iter() .iter()
.enumerate() .enumerate()
.map( .map(|(i, field)| {
|(i, field)| { let mut field_expr = if is_enum {
let mut field_expr = if is_enum { let id = Ident::new(format!("__field{}", i));
let id = Ident::new(format!("__field{}", i)); quote!(#id)
quote!(#id) } else {
} else { get_field(params, field, i)
get_field(params, field, i) };
};
let skip = field let skip = field
.attrs .attrs
.skip_serializing_if() .skip_serializing_if()
.map(|path| quote!(#path(#field_expr))); .map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() { if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
} }
let ser = quote! { let ser = quote! {
try!(#func(&mut __serde_state, #field_expr)); try!(#func(&mut __serde_state, #field_expr));
}; };
match skip { match skip {
None => ser, None => ser,
Some(skip) => quote!(if !#skip { #ser }), Some(skip) => quote!(if !#skip { #ser }),
} }
}, })
)
.collect() .collect()
} }
@@ -898,44 +850,42 @@ fn serialize_struct_visitor(
fields fields
.iter() .iter()
.filter(|&field| !field.attrs.skip_serializing()) .filter(|&field| !field.attrs.skip_serializing())
.map( .map(|field| {
|field| { let field_ident = field.ident.clone().expect("struct has unnamed field");
let field_ident = field.ident.clone().expect("struct has unnamed field"); let mut field_expr = if is_enum {
let mut field_expr = if is_enum { quote!(#field_ident)
quote!(#field_ident) } else {
} else { get_field(params, field, field_ident)
get_field(params, field, field_ident) };
};
let key_expr = field.attrs.name().serialize_name(); let key_expr = field.attrs.name().serialize_name();
let skip = field let skip = field
.attrs .attrs
.skip_serializing_if() .skip_serializing_if()
.map(|path| quote!(#path(#field_expr))); .map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() { if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
} }
let ser = quote! { let ser = quote! {
try!(#func(&mut __serde_state, #key_expr, #field_expr)); try!(#func(&mut __serde_state, #key_expr, #field_expr));
}; };
match skip { match skip {
None => ser, None => ser,
Some(skip) => { Some(skip) => {
quote! { quote! {
if !#skip { if !#skip {
#ser #ser
} else { } else {
try!(#skip_func(&mut __serde_state, #key_expr)); try!(#skip_func(&mut __serde_state, #key_expr));
}
} }
} }
} }
}, }
) })
.collect() .collect()
} }
@@ -945,10 +895,7 @@ fn wrap_serialize_field_with(
serialize_with: &syn::Path, serialize_with: &syn::Path,
field_expr: Tokens, field_expr: Tokens,
) -> Tokens { ) -> Tokens {
wrap_serialize_with(params, wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
serialize_with,
&[field_ty],
&[quote!(#field_expr)])
} }
fn wrap_serialize_variant_with( fn wrap_serialize_variant_with(
@@ -957,15 +904,24 @@ fn wrap_serialize_variant_with(
variant: &Variant, variant: &Variant,
) -> Tokens { ) -> Tokens {
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
let field_exprs: Vec<_> = variant.fields.iter() let field_exprs: Vec<_> = variant
.fields
.iter()
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| {
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)), let id = field
|id| id.clone()); .ident
.as_ref()
.map_or_else(|| Ident::new(format!("__field{}", i)), |id| id.clone());
quote!(#id) quote!(#id)
}) })
.collect(); .collect();
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice()) wrap_serialize_with(
params,
serialize_with,
field_tys.as_slice(),
field_exprs.as_slice(),
)
} }
fn wrap_serialize_with( fn wrap_serialize_with(
@@ -1014,7 +970,11 @@ fn wrap_serialize_with(
// //
// where we want to omit the `mut` to avoid a warning. // where we want to omit the `mut` to avoid a warning.
fn mut_if(is_mut: bool) -> Option<Tokens> { fn mut_if(is_mut: bool) -> Option<Tokens> {
if is_mut { Some(quote!(mut)) } else { None } if is_mut {
Some(quote!(mut))
} else {
None
}
} }
fn get_field<I>(params: &Parameters, field: &Field, ident: I) -> Tokens fn get_field<I>(params: &Parameters, field: &Field, ident: I) -> Tokens
+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.18.1" # 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."
+57 -42
View File
@@ -49,27 +49,25 @@ impl<'a> Container<'a> {
let attrs = attr::Container::from_ast(cx, item); let attrs = attr::Container::from_ast(cx, item);
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, &attrs.default()))
}
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, &attrs.default());
Body::Struct(style, fields) Body::Struct(style, fields)
} }
}; };
match body { match body {
Body::Enum(ref mut variants) => { Body::Enum(ref mut variants) => for ref mut variant in variants {
for ref mut variant in variants { variant.attrs.rename_by_rule(attrs.rename_all());
variant.attrs.rename_by_rule(attrs.rename_all()); for ref mut field in &mut variant.fields {
for ref mut field in &mut variant.fields { field.attrs.rename_by_rule(variant.attrs.rename_all());
field.attrs.rename_by_rule(variant.attrs.rename_all());
}
} }
} },
Body::Struct(_, ref mut fields) => { Body::Struct(_, ref mut fields) => for field in fields {
for field in fields { field.attrs.rename_by_rule(attrs.rename_all());
field.attrs.rename_by_rule(attrs.rename_all()); },
}
}
} }
let item = Container { let item = Container {
@@ -98,46 +96,63 @@ impl<'a> Body<'a> {
} }
} }
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> { fn enum_from_ast<'a>(
cx: &Ctxt,
variants: &'a [syn::Variant],
container_default: &attr::Default,
) -> Vec<Variant<'a>> {
variants variants
.iter() .iter()
.map( .map(|variant| {
|variant| { let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) = struct_from_ast(cx, &variant.data); let (style, fields) =
Variant { struct_from_ast(cx, &variant.data, Some(&attrs), container_default);
ident: variant.ident.clone(), Variant {
attrs: attr::Variant::from_ast(cx, variant), ident: variant.ident.clone(),
style: style, attrs: attrs,
fields: fields, style: style,
} fields: fields,
}, }
) })
.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>,
container_default: &attr::Default,
) -> (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) => (
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => { Style::Struct,
(Style::Newtype, fields_from_ast(cx, fields)) fields_from_ast(cx, fields, attrs, container_default),
} ),
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)), syn::VariantData::Tuple(ref fields) if fields.len() == 1 => (
Style::Newtype,
fields_from_ast(cx, fields, attrs, container_default),
),
syn::VariantData::Tuple(ref fields) => (
Style::Tuple,
fields_from_ast(cx, fields, attrs, container_default),
),
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>,
container_default: &attr::Default,
) -> Vec<Field<'a>> {
fields fields
.iter() .iter()
.enumerate() .enumerate()
.map( .map(|(i, field)| Field {
|(i, field)| { ident: field.ident.clone(),
Field { attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ident: field.ident.clone(), ty: &field.ty,
attrs: attr::Field::from_ast(cx, i, field), })
ty: &field.ty,
}
},
)
.collect() .collect()
} }
+139 -113
View File
@@ -164,6 +164,15 @@ pub enum Identifier {
Variant, Variant,
} }
impl Identifier {
pub fn is_some(self) -> bool {
match self {
Identifier::No => false,
Identifier::Field | Identifier::Variant => true,
}
}
}
impl Container { impl Container {
/// Extract out the `#[serde(...)]` attributes from an item. /// Extract out the `#[serde(...)]` attributes from an item.
pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self {
@@ -207,11 +216,11 @@ impl Container {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match RenameRule::from_str(&s) { match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => { Err(()) => cx.error(format!(
cx.error(format!("unknown rename rule for #[serde(rename_all \ "unknown rename rule for #[serde(rename_all \
= {:?})]", = {:?})]",
s)) s
} )),
} }
} }
} }
@@ -222,19 +231,15 @@ impl Container {
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
MetaItem(Word(ref name)) if name == "default" => { MetaItem(Word(ref name)) if name == "default" => match item.body {
match item.body { syn::Body::Struct(syn::VariantData::Struct(_)) => {
syn::Body::Struct(syn::VariantData::Struct(_)) => { default.set(Default::Default);
default.set(Default::Default);
}
_ => {
cx.error(
"#[serde(default)] can only be used on structs \
with named fields",
)
}
} }
} _ => cx.error(
"#[serde(default)] can only be used on structs \
with named fields",
),
},
// Parse `#[serde(default = "...")]` // Parse `#[serde(default = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "default" => { MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
@@ -243,12 +248,10 @@ impl Container {
syn::Body::Struct(syn::VariantData::Struct(_)) => { syn::Body::Struct(syn::VariantData::Struct(_)) => {
default.set(Default::Path(path)); default.set(Default::Path(path));
} }
_ => { _ => cx.error(
cx.error( "#[serde(default = \"...\")] can only be used \
"#[serde(default = \"...\")] can only be used \ on structs with named fields",
on structs with named fields", ),
)
}
} }
} }
} }
@@ -256,7 +259,8 @@ impl Container {
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit)
{
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
} }
@@ -271,16 +275,14 @@ impl Container {
} }
// Parse `#[serde(untagged)]` // Parse `#[serde(untagged)]`
MetaItem(Word(ref name)) if name == "untagged" => { MetaItem(Word(ref name)) if name == "untagged" => match item.body {
match item.body { syn::Body::Enum(_) => {
syn::Body::Enum(_) => { untagged.set_true();
untagged.set_true();
}
syn::Body::Struct(_) => {
cx.error("#[serde(untagged)] can only be used on enums")
}
} }
} syn::Body::Struct(_) => {
cx.error("#[serde(untagged)] can only be used on enums")
}
},
// Parse `#[serde(tag = "type")]` // Parse `#[serde(tag = "type")]`
MetaItem(NameValue(ref name, ref lit)) if name == "tag" => { MetaItem(NameValue(ref name, ref lit)) if name == "tag" => {
@@ -303,12 +305,10 @@ impl Container {
syn::Body::Enum(_) => { syn::Body::Enum(_) => {
content.set(s); content.set(s);
} }
syn::Body::Struct(_) => { syn::Body::Struct(_) => cx.error(
cx.error( "#[serde(content = \"...\")] can only be used on \
"#[serde(content = \"...\")] can only be used on \ enums",
enums", ),
)
}
} }
} }
} }
@@ -345,8 +345,10 @@ impl Container {
} }
MetaItem(ref meta_item) => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde container attribute `{}`", cx.error(format!(
meta_item.name())); "unknown serde container attribute `{}`",
meta_item.name()
));
} }
Literal(_) => { Literal(_) => {
@@ -434,13 +436,12 @@ fn decide_tag(
if let syn::Body::Enum(ref variants) = item.body { if let syn::Body::Enum(ref variants) = item.body {
for variant in variants { for variant in variants {
match variant.data { match variant.data {
syn::VariantData::Struct(_) | syn::VariantData::Struct(_) | syn::VariantData::Unit => {}
syn::VariantData::Unit => {}
syn::VariantData::Tuple(ref fields) => { syn::VariantData::Tuple(ref fields) => {
if fields.len() != 1 { if fields.len() != 1 {
cx.error( cx.error(
"#[serde(tag = \"...\")] cannot be used with tuple \ "#[serde(tag = \"...\")] cannot be used with tuple \
variants", variants",
); );
break; break;
} }
@@ -455,21 +456,19 @@ fn decide_tag(
EnumTag::External // doesn't matter, will error EnumTag::External // doesn't matter, will error
} }
(false, None, Some(_)) => { (false, None, Some(_)) => {
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together",); cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
EnumTag::External EnumTag::External
} }
(true, None, Some(_)) => { (true, None, Some(_)) => {
cx.error("untagged enum cannot have #[serde(content = \"...\")]"); cx.error("untagged enum cannot have #[serde(content = \"...\")]");
EnumTag::External EnumTag::External
} }
(false, Some(tag), Some(content)) => { (false, Some(tag), Some(content)) => EnumTag::Adjacent {
EnumTag::Adjacent { tag: tag,
tag: tag, content: content,
content: content, },
}
}
(true, Some(_), Some(_)) => { (true, Some(_), Some(_)) => {
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",); cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
EnumTag::External EnumTag::External
} }
} }
@@ -484,7 +483,7 @@ fn decide_identifier(
match (&item.body, field_identifier.get(), variant_identifier.get()) { match (&item.body, field_identifier.get(), variant_identifier.get()) {
(_, false, false) => Identifier::No, (_, false, false) => Identifier::No,
(_, true, true) => { (_, true, true) => {
cx.error("`field_identifier` and `variant_identifier` cannot both be set",); cx.error("`field_identifier` and `variant_identifier` cannot both be set");
Identifier::No Identifier::No
} }
(&syn::Body::Struct(_), true, false) => { (&syn::Body::Struct(_), true, false) => {
@@ -512,6 +511,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 +524,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 {
@@ -549,11 +550,11 @@ impl Variant {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match RenameRule::from_str(&s) { match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => { Err(()) => cx.error(format!(
cx.error(format!("unknown rename rule for #[serde(rename_all \ "unknown rename rule for #[serde(rename_all \
= {:?})]", = {:?})]",
s)) s
} )),
} }
} }
} }
@@ -599,8 +600,21 @@ 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()
));
} }
Literal(_) => { Literal(_) => {
@@ -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,13 @@ 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>,
container_default: &Default,
) -> 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 +739,18 @@ 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")]`
@@ -763,7 +795,7 @@ impl Field {
MetaItem(Word(ref name)) if name == "skip" => { MetaItem(Word(ref name)) if name == "skip" => {
skip_serializing.set_true(); skip_serializing.set_true();
skip_deserializing.set_true(); skip_deserializing.set_true();
}, }
// Parse `#[serde(skip_serializing_if = "...")]` // Parse `#[serde(skip_serializing_if = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => { MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
@@ -801,7 +833,8 @@ impl Field {
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit)
{
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
} }
@@ -828,13 +861,10 @@ impl Field {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
for lifetime in &lifetimes { for lifetime in &lifetimes {
if !borrowable.contains(lifetime) { if !borrowable.contains(lifetime) {
cx.error( cx.error(format!(
format!( "field `{}` does not have lifetime {}",
"field `{}` does not have lifetime {}", ident, lifetime.ident
ident, ));
lifetime.ident
),
);
} }
} }
borrowed_lifetimes.set(lifetimes); borrowed_lifetimes.set(lifetimes);
@@ -850,7 +880,10 @@ impl Field {
} }
MetaItem(ref meta_item) => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde field attribute `{}`", meta_item.name()),); cx.error(format!(
"unknown serde field attribute `{}`",
meta_item.name()
));
} }
Literal(_) => { Literal(_) => {
@@ -860,9 +893,10 @@ impl Field {
} }
} }
// Is skip_deserializing, initialize the field to Default::default() // Is skip_deserializing, initialize the field to Default::default() unless a different
// unless a different default is specified by `#[serde(default = "...")]` // default is specified by `#[serde(default = "...")]` on ourselves or our container (e.g.
if skip_deserializing.0.value.is_some() { // the struct we are in).
if container_default == &Default::None && skip_deserializing.0.value.is_some() {
default.set_if_none(Default::Default); default.set_if_none(Default::Default);
} }
@@ -997,13 +1031,11 @@ where
} }
_ => { _ => {
cx.error( cx.error(format!(
format!( "malformed {0} attribute, expected `{0}(serialize = ..., \
"malformed {0} attribute, expected `{0}(serialize = ..., \ deserialize = ...)`",
deserialize = ...)`", attr_name
attr_name ));
),
);
return Err(()); return Err(());
} }
} }
@@ -1039,13 +1071,10 @@ fn get_string_from_lit(
if let syn::Lit::Str(ref s, _) = *lit { if let syn::Lit::Str(ref s, _) = *lit {
Ok(s.clone()) Ok(s.clone())
} else { } else {
cx.error( cx.error(format!(
format!( "expected serde {} attribute to be a string: `{} = \"...\"`",
"expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name
attr_name, ));
meta_item_name
),
);
Err(()) Err(())
} }
} }
@@ -1076,11 +1105,12 @@ fn parse_lit_into_where(
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Ty, ()> { fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Ty, ()> {
let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit));
syn::parse_type(&string).map_err( syn::parse_type(&string).map_err(|_| {
|_| { cx.error(format!(
cx.error(format!("failed to parse type: {} = {:?}", attr_name, string),) "failed to parse type: {} = {:?}",
}, attr_name, string
) ))
})
} }
// Parses a string literal like "'a + 'b + 'c" containing a nonempty list of // Parses a string literal like "'a + 'b + 'c" containing a nonempty list of
@@ -1111,7 +1141,7 @@ fn parse_lit_into_lifetimes(
return Ok(set); return Ok(set);
} }
} }
Err(cx.error(format!("failed to parse borrowed lifetimes: {:?}", string)),) Err(cx.error(format!("failed to parse borrowed lifetimes: {:?}", string)))
} }
// Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". // Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T".
@@ -1155,8 +1185,8 @@ fn is_cow(ty: &syn::Ty, elem: &str) -> bool {
return false; return false;
} }
}; };
seg.ident == "Cow" && params.lifetimes.len() == 1 && seg.ident == "Cow" && params.lifetimes.len() == 1
params.types == vec![syn::parse_type(elem).unwrap()] && params.bindings.is_empty() && params.types == vec![syn::parse_type(elem).unwrap()] && params.bindings.is_empty()
} }
// Whether the type looks like it might be `&T` where elem="T". This can have // Whether the type looks like it might be `&T` where elem="T". This can have
@@ -1182,8 +1212,8 @@ fn is_cow(ty: &syn::Ty, elem: &str) -> bool {
fn is_rptr(ty: &syn::Ty, elem: &str) -> bool { fn is_rptr(ty: &syn::Ty, elem: &str) -> bool {
match *ty { match *ty {
syn::Ty::Rptr(Some(_), ref mut_ty) => { syn::Ty::Rptr(Some(_), ref mut_ty) => {
mut_ty.mutability == syn::Mutability::Immutable && mut_ty.mutability == syn::Mutability::Immutable
mut_ty.ty == syn::parse_type(elem).unwrap() && mut_ty.ty == syn::parse_type(elem).unwrap()
} }
_ => false, _ => false,
} }
@@ -1204,7 +1234,7 @@ fn borrowable_lifetimes(
let mut lifetimes = BTreeSet::new(); let mut lifetimes = BTreeSet::new();
collect_lifetimes(ty, &mut lifetimes); collect_lifetimes(ty, &mut lifetimes);
if lifetimes.is_empty() { if lifetimes.is_empty() {
Err(cx.error(format!("field `{}` has no lifetimes to borrow", name)),) Err(cx.error(format!("field `{}` has no lifetimes to borrow", name)))
} else { } else {
Ok(lifetimes) Ok(lifetimes)
} }
@@ -1212,9 +1242,7 @@ fn borrowable_lifetimes(
fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet<syn::Lifetime>) { fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet<syn::Lifetime>) {
match *ty { match *ty {
syn::Ty::Slice(ref elem) | syn::Ty::Slice(ref elem) | syn::Ty::Array(ref elem, _) | syn::Ty::Paren(ref elem) => {
syn::Ty::Array(ref elem, _) |
syn::Ty::Paren(ref elem) => {
collect_lifetimes(elem, out); collect_lifetimes(elem, out);
} }
syn::Ty::Ptr(ref elem) => { syn::Ty::Ptr(ref elem) => {
@@ -1224,11 +1252,9 @@ fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet<syn::Lifetime>) {
out.extend(lifetime.iter().cloned()); out.extend(lifetime.iter().cloned());
collect_lifetimes(&elem.ty, out); collect_lifetimes(&elem.ty, out);
} }
syn::Ty::Tup(ref elems) => { syn::Ty::Tup(ref elems) => for elem in elems {
for elem in elems { collect_lifetimes(elem, out);
collect_lifetimes(elem, out); },
}
}
syn::Ty::Path(ref qself, ref path) => { syn::Ty::Path(ref qself, ref path) => {
if let Some(ref qself) = *qself { if let Some(ref qself) = *qself {
collect_lifetimes(&qself.ty, out); collect_lifetimes(&qself.ty, out);
@@ -1245,11 +1271,11 @@ fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet<syn::Lifetime>) {
} }
} }
} }
syn::Ty::BareFn(_) | syn::Ty::BareFn(_)
syn::Ty::Never | | syn::Ty::Never
syn::Ty::TraitObject(_) | | syn::Ty::TraitObject(_)
syn::Ty::ImplTrait(_) | | syn::Ty::ImplTrait(_)
syn::Ty::Infer | | syn::Ty::Infer
syn::Ty::Mac(_) => {} | syn::Ty::Mac(_) => {}
} }
} }
+54 -18
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::*;
@@ -28,7 +31,7 @@ pub enum RenameRule {
/// Rename direct children to "kebab-case" style. /// Rename direct children to "kebab-case" style.
KebabCase, KebabCase,
/// Rename direct children to "SCREAMING-KEBAB-CASE" style. /// Rename direct children to "SCREAMING-KEBAB-CASE" style.
ScreamingKebabCase ScreamingKebabCase,
} }
impl RenameRule { impl RenameRule {
@@ -49,7 +52,9 @@ impl RenameRule {
} }
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-") ScreamingKebabCase => ScreamingSnakeCase
.apply_to_variant(variant)
.replace('_', "-"),
} }
} }
@@ -77,7 +82,7 @@ impl RenameRule {
} }
ScreamingSnakeCase => field.to_ascii_uppercase(), ScreamingSnakeCase => field.to_ascii_uppercase(),
KebabCase => field.replace('_', "-"), KebabCase => field.replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-") ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
} }
} }
} }
@@ -101,13 +106,28 @@ impl FromStr for RenameRule {
#[test] #[test]
fn rename_variants() { fn rename_variants() {
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in &[
&[ (
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"), "Outcome",
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"), "outcome",
("A", "a", "a", "a", "A", "a", "A"), "outcome",
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"), "outcome",
] { "OUTCOME",
"outcome",
"OUTCOME",
),
(
"VeryTasty",
"verytasty",
"veryTasty",
"very_tasty",
"VERY_TASTY",
"very-tasty",
"VERY-TASTY",
),
("A", "a", "a", "a", "A", "a", "A"),
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
] {
assert_eq!(None.apply_to_variant(original), original); assert_eq!(None.apply_to_variant(original), original);
assert_eq!(LowerCase.apply_to_variant(original), lower); assert_eq!(LowerCase.apply_to_variant(original), lower);
assert_eq!(PascalCase.apply_to_variant(original), original); assert_eq!(PascalCase.apply_to_variant(original), original);
@@ -115,19 +135,35 @@ fn rename_variants() {
assert_eq!(SnakeCase.apply_to_variant(original), snake); assert_eq!(SnakeCase.apply_to_variant(original), snake);
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
assert_eq!(KebabCase.apply_to_variant(original), kebab); assert_eq!(KebabCase.apply_to_variant(original), kebab);
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab); assert_eq!(
ScreamingKebabCase.apply_to_variant(original),
screaming_kebab
);
} }
} }
#[test] #[test]
fn rename_fields() { fn rename_fields() {
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in for &(original, pascal, camel, screaming, kebab, screaming_kebab) in &[
&[ (
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"), "outcome",
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"), "Outcome",
("a", "A", "a", "A", "a", "A"), "outcome",
("z42", "Z42", "z42", "Z42", "z42", "Z42"), "OUTCOME",
] { "outcome",
"OUTCOME",
),
(
"very_tasty",
"VeryTasty",
"veryTasty",
"VERY_TASTY",
"very-tasty",
"VERY-TASTY",
),
("a", "A", "a", "A", "a", "A"),
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
] {
assert_eq!(None.apply_to_field(original), original); assert_eq!(None.apply_to_field(original), original);
assert_eq!(PascalCase.apply_to_field(original), pascal); assert_eq!(PascalCase.apply_to_field(original), pascal);
assert_eq!(CamelCase.apply_to_field(original), camel); assert_eq!(CamelCase.apply_to_field(original), camel);
+40 -21
View File
@@ -31,7 +31,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
if cont.body.has_getter() && cont.attrs.remote().is_none() { if cont.body.has_getter() && cont.attrs.remote().is_none() {
cx.error( cx.error(
"#[serde(getter = \"...\")] can only be used in structs \ "#[serde(getter = \"...\")] can only be used in structs \
that have #[serde(remote = \"...\")]", that have #[serde(remote = \"...\")]",
); );
} }
} }
@@ -53,10 +53,13 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
}; };
for (i, variant) in variants.iter().enumerate() { for (i, variant) in variants.iter().enumerate() {
match (variant.style, cont.attrs.identifier(), variant.attrs.other()) { match (
variant.style,
cont.attrs.identifier(),
variant.attrs.other(),
) {
// The `other` attribute may only be used in a field_identifier. // The `other` attribute may only be used in a field_identifier.
(_, Identifier::Variant, true) | (_, Identifier::Variant, true) | (_, Identifier::No, true) => {
(_, Identifier::No, true) => {
cx.error("#[serde(other)] may only be used inside a field_identifier"); cx.error("#[serde(other)] may only be used inside a field_identifier");
} }
@@ -109,42 +112,58 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
for variant in variants.iter() { for variant in variants.iter() {
if variant.attrs.serialize_with().is_some() { if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() { if variant.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \ cx.error(format!(
#[serde(skip_serializing)]", variant.ident)); "variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]",
variant.ident
));
} }
for (i, field) in variant.fields.iter().enumerate() { for (i, field) in variant.fields.iter().enumerate() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i), let ident = field
|ident| format!("`{}`", ident)); .ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
if field.attrs.skip_serializing() { if field.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \ cx.error(format!(
a field {} marked with #[serde(skip_serializing)]", "variant `{}` cannot have both #[serde(serialize_with)] and \
variant.ident, ident)); a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident
));
} }
if field.attrs.skip_serializing_if().is_some() { if field.attrs.skip_serializing_if().is_some() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \ cx.error(format!(
a field {} marked with #[serde(skip_serializing_if)]", "variant `{}` cannot have both #[serde(serialize_with)] and \
variant.ident, ident)); a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident
));
} }
} }
} }
if variant.attrs.deserialize_with().is_some() { if variant.attrs.deserialize_with().is_some() {
if variant.attrs.skip_deserializing() { if variant.attrs.skip_deserializing() {
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \ cx.error(format!(
#[serde(skip_deserializing)]", variant.ident)); "variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]",
variant.ident
));
} }
for (i, field) in variant.fields.iter().enumerate() { for (i, field) in variant.fields.iter().enumerate() {
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i), let ident = field
|ident| format!("`{}`", ident)); .ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \ cx.error(format!(
and a field {} marked with #[serde(skip_deserializing)]", "variant `{}` cannot have both #[serde(deserialize_with)] \
variant.ident, ident)); and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident
));
} }
} }
} }
+3 -1
View File
@@ -16,7 +16,9 @@ pub struct Ctxt {
impl Ctxt { impl Ctxt {
pub fn new() -> Self { pub fn new() -> Self {
Ctxt { errors: RefCell::new(Some(Vec::new())) } Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
} }
pub fn error<T: Display>(&self, msg: T) { pub fn error<T: Display>(&self, msg: T) {
+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.18.1")]
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.25" # 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]
+24 -41
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,21 +183,28 @@ 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);
} let mut deserialized_val = match T::deserialize(&mut de) {
Ok(v) => {
// Not public API assert_eq!(v, *value);
#[doc(hidden)] v
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) {
Ok(v) => assert_eq!(v, *value),
Err(e) => panic!("tokens failed to deserialize: {}", e), Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
} }
// Do the same thing for deserialize_in_place. This isn't *great* because a
// no-op impl of deserialize_in_place can technically succeed here. Still,
// this should catch a lot of junk.
let mut de = Deserializer::new(tokens);
match T::deserialize_in_place(&mut de, &mut deserialized_val) {
Ok(()) => {
assert_eq!(deserialized_val, *value);
}
Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
}
if de.remaining() > 0 { if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining()); panic!("{} remaining tokens", de.remaining());
} }
@@ -248,7 +231,7 @@ where
/// ///
/// assert_de_tokens_error::<S>( /// assert_de_tokens_error::<S>(
/// &[ /// &[
/// Token::Struct { name: "S", len: 1 }, /// Token::Struct { name: "S", len: 2 },
/// Token::Str("x"), /// Token::Str("x"),
/// ], /// ],
/// "unknown field `x`, expected `a` or `b`", /// "unknown field `x`, expected `a` or `b`",
+664
View File
@@ -0,0 +1,664 @@
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::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
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);
+89 -88
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> {
@@ -102,15 +95,11 @@ impl<'de> Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let value = try!( let value = try!(visitor.visit_seq(DeserializerSeqVisitor {
visitor.visit_seq( de: self,
DeserializerSeqVisitor { len: len,
de: self, end: end,
len: len, },));
end: end.clone(),
},
)
);
assert_next_token!(self, end); assert_next_token!(self, end);
Ok(value) Ok(value)
} }
@@ -124,15 +113,11 @@ impl<'de> Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let value = try!( let value = try!(visitor.visit_map(DeserializerMapVisitor {
visitor.visit_map( de: self,
DeserializerMapVisitor { len: len,
de: self, end: end,
len: len, },));
end: end.clone(),
},
)
);
assert_next_token!(self, end); assert_next_token!(self, end);
Ok(value) Ok(value)
} }
@@ -172,15 +157,16 @@ 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,18 +188,29 @@ 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(
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Any),) self,
} Token::Str(variant),
Token::TupleVariant { name: _, variant, len: _ } => { EnumFormat::Any,
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Seq),) )),
} Token::TupleVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
Token::StructVariant { name: _, variant, len: _ } => { self,
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Map),) Token::Str(variant),
} EnumFormat::Seq,
Token::SeqEnd | Token::TupleEnd | Token::TupleStructEnd | Token::MapEnd | )),
Token::StructEnd | Token::TupleVariantEnd | Token::StructVariantEnd => { Token::StructVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
self,
Token::Str(variant),
EnumFormat::Map,
)),
Token::SeqEnd
| Token::TupleEnd
| Token::TupleStructEnd
| Token::MapEnd
| Token::StructEnd
| Token::TupleVariantEnd
| Token::StructVariantEnd => {
unexpected!(token); unexpected!(token);
} }
} }
@@ -224,8 +221,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::Unit | Token::Unit | Token::None => {
Token::None => {
self.next_token(); self.next_token();
visitor.visit_none() visitor.visit_none()
} }
@@ -252,10 +248,11 @@ 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 +266,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()
} }
@@ -277,12 +274,16 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
} }
} }
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, Error> fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Error>
where where
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)
} }
@@ -295,20 +296,19 @@ 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::Unit | Token::Unit | Token::UnitStruct { .. } => {
Token::UnitStruct { name: _ } => {
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 +330,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 +360,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 +373,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 +456,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 +477,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 +490,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 +503,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 {
@@ -518,7 +513,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
unexpected!(token); unexpected!(token);
} }
} }
Token::Seq { len: Some(enum_len) } => { Token::Seq {
len: Some(enum_len),
} => {
let token = self.de.next_token(); let token = self.de.next_token();
if len == enum_len { if len == enum_len {
@@ -531,12 +528,16 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
} }
} }
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value, Error> fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where where
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 {
@@ -546,7 +547,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
unexpected!(token); unexpected!(token);
} }
} }
Token::Map { len: Some(enum_len) } => { Token::Map {
len: Some(enum_len),
} => {
let token = self.de.next_token(); let token = self.de.next_token();
if fields.len() == enum_len { if fields.len() == enum_len {
@@ -594,10 +597,8 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
{ {
match self.variant.take() { match self.variant.take() {
Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(Token::Bytes(variant)) => { Some(Token::Bytes(variant)) => seed.deserialize(BytesDeserializer { value: variant })
seed.deserialize(BytesDeserializer { value: variant }) .map(Some),
.map(Some)
}
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other), Some(other) => unexpected!(other),
None => Ok(None), None => Ok(None),
+9 -5
View File
@@ -9,7 +9,7 @@
use std::error; use std::error;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use serde::{ser, de}; use serde::{de, ser};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Error { pub struct Error {
@@ -17,14 +17,18 @@ 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(),
}
} }
} }
+11 -6
View File
@@ -155,7 +155,13 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.17")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.25")]
#![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_debug, use_self))]
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
@@ -164,16 +170,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)]
+45 -27
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.
@@ -47,25 +40,43 @@ impl<'a> Serializer<'a> {
macro_rules! assert_next_token { macro_rules! assert_next_token {
($ser:expr, $expected:ident) => { ($ser:expr, $expected:ident) => {
assert_next_token!($ser, $expected, Token::$expected, true); assert_next_token!($ser, stringify!($expected), Token::$expected, true);
}; };
($ser:expr, $expected:ident($v:expr)) => { ($ser:expr, $expected:ident($v:expr)) => {
assert_next_token!($ser, $expected, Token::$expected(v), v == $v); assert_next_token!(
$ser,
format_args!("{}({:?})", stringify!($expected), $v),
Token::$expected(v),
v == $v
);
}; };
($ser:expr, $expected:ident { $($k:ident),* }) => { ($ser:expr, $expected:ident { $($k:ident),* }) => {
let compare = ($($k,)*); let compare = ($($k,)*);
assert_next_token!($ser, $expected, Token::$expected { $($k),* }, ($($k,)*) == compare); let field_format = || {
use std::fmt::Write;
let mut buffer = String::new();
$(
write!(&mut buffer, "{}: {:?}, ", stringify!($k), $k).unwrap();
)*
buffer
};
assert_next_token!(
$ser,
format_args!("{} {{ {}}}", stringify!($expected), field_format()),
Token::$expected { $($k),* },
($($k,)*) == compare
);
}; };
($ser:expr, $expected:ident, $pat:pat, $guard:expr) => { ($ser:expr, $expected:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() { match $ser.next_token() {
Some($pat) if $guard => {} Some($pat) if $guard => {}
Some(other) => { Some(other) => {
panic!("expected Token::{} but serialized as {}", panic!("expected Token::{} but serialized as {}",
stringify!($expected), other); $expected, other);
} }
None => { None => {
panic!("expected Token::{} after end of serialized tokens", panic!("expected Token::{} after end of serialized tokens",
stringify!($expected)); $expected);
} }
} }
}; };
@@ -254,10 +265,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 +300,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.");
}
}
} }
} }
+18 -4
View File
@@ -232,7 +232,10 @@ pub enum Token {
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]); /// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]);
/// # } /// # }
/// ``` /// ```
UnitVariant { name: &'static str, variant: &'static str }, UnitVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a serialized newtype struct of the given name. /// The header to a serialized newtype struct of the given name.
/// ///
@@ -286,7 +289,10 @@ pub enum Token {
/// ]); /// ]);
/// # } /// # }
/// ``` /// ```
NewtypeVariant { name: &'static str, variant: &'static str }, NewtypeVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a sequence. /// The header to a sequence.
/// ///
@@ -391,7 +397,11 @@ pub enum Token {
/// ]); /// ]);
/// # } /// # }
/// ``` /// ```
TupleVariant { name: &'static str, variant: &'static str, len: usize }, TupleVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a tuple variant. /// An indicator of the end of a tuple variant.
TupleVariantEnd, TupleVariantEnd,
@@ -488,7 +498,11 @@ pub enum Token {
/// ]); /// ]);
/// # } /// # }
/// ``` /// ```
StructVariant { name: &'static str, variant: &'static str, len: usize }, StructVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a struct variant. /// An indicator of the end of a struct variant.
StructVariantEnd, StructVariantEnd,
+2 -2
View File
@@ -11,8 +11,8 @@ unstable = ["serde/unstable", "compiletest_rs"]
fnv = "1.0" fnv = "1.0"
rustc-serialize = "0.3.16" rustc-serialize = "0.3.16"
serde = { path = "../serde", features = ["rc"] } serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive" } serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" } serde_test = { path = "../serde_test" }
[dependencies] [dependencies]
compiletest_rs = { version = "0.2", optional = true } compiletest_rs = { version = "0.3", optional = true }
@@ -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() {}
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -13,7 +13,7 @@ extern crate serde;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
extern crate serde_test; extern crate serde_test;
use serde_test::{Token, assert_de_tokens, assert_de_tokens_error}; use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
use std::borrow::Cow; use std::borrow::Cow;
@@ -87,18 +87,18 @@ fn test_struct() {
assert_de_tokens( assert_de_tokens(
&Borrowing { &Borrowing {
bs: "str", bs: "str",
bb: b"bytes", bb: b"bytes",
}, },
&[ &[
Token::Struct { name: "Borrowing", len: 2 }, Token::Struct {
name: "Borrowing",
len: 2,
},
Token::BorrowedStr("bs"), Token::BorrowedStr("bs"),
Token::BorrowedStr("str"), Token::BorrowedStr("str"),
Token::BorrowedStr("bb"), Token::BorrowedStr("bb"),
Token::BorrowedBytes(b"bytes"), Token::BorrowedBytes(b"bytes"),
Token::StructEnd, Token::StructEnd,
], ],
); );
@@ -115,14 +115,14 @@ fn test_cow() {
} }
let tokens = &[ let tokens = &[
Token::Struct { name: "Cows", len: 2 }, Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"), Token::Str("copied"),
Token::BorrowedStr("copied"), Token::BorrowedStr("copied"),
Token::Str("borrowed"), Token::Str("borrowed"),
Token::BorrowedStr("borrowed"), Token::BorrowedStr("borrowed"),
Token::StructEnd, Token::StructEnd,
]; ];
+51 -21
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;
@@ -83,6 +83,26 @@ struct StructSkipAll {
a: i32, a: i32,
} }
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructSkipDefault {
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructSkipDefaultGeneric<T> {
#[serde(skip_deserializing)]
t: T,
}
impl Default for StructSkipDefault {
fn default() -> Self {
StructSkipDefault { a: 16 }
}
}
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct StructSkipAllDenyUnknown { struct StructSkipAllDenyUnknown {
@@ -98,7 +118,11 @@ enum Enum {
Unit, Unit,
Simple(i32), Simple(i32),
Seq(i32, i32, i32), Seq(i32, i32, i32),
Map { a: i32, b: i32, c: i32 }, Map {
a: i32,
b: i32,
c: i32,
},
} }
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
@@ -112,7 +136,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 +144,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 +192,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();
@@ -544,7 +566,7 @@ declare_tests! {
Token::MapEnd, Token::MapEnd,
], ],
Struct { a: 1, b: 2, c: 0 } => &[ Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 }, Token::Struct { name: "Struct", len: 2 },
Token::Str("a"), Token::Str("a"),
Token::I32(1), Token::I32(1),
@@ -576,7 +598,7 @@ declare_tests! {
Token::MapEnd, Token::MapEnd,
], ],
Struct { a: 1, b: 2, c: 0 } => &[ Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 }, Token::Struct { name: "Struct", len: 2 },
Token::Str("a"), Token::Str("a"),
Token::I32(1), Token::I32(1),
@@ -597,7 +619,7 @@ declare_tests! {
Token::StructEnd, Token::StructEnd,
], ],
StructSkipAll { a: 0 } => &[ StructSkipAll { a: 0 } => &[
Token::Struct { name: "StructSkipAll", len: 1 }, Token::Struct { name: "StructSkipAll", len: 0 },
Token::Str("a"), Token::Str("a"),
Token::I32(1), Token::I32(1),
@@ -606,6 +628,12 @@ declare_tests! {
Token::StructEnd, Token::StructEnd,
], ],
} }
test_struct_skip_default {
StructSkipDefault { a: 16 } => &[
Token::Struct { name: "StructSkipDefault", len: 0 },
Token::StructEnd,
],
}
test_struct_skip_all_deny_unknown { test_struct_skip_all_deny_unknown {
StructSkipAllDenyUnknown { a: 0 } => &[ StructSkipAllDenyUnknown { a: 0 } => &[
Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 }, Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
@@ -614,7 +642,7 @@ declare_tests! {
} }
test_struct_default { test_struct_default {
StructDefault { a: 50, b: "overwritten".to_string() } => &[ StructDefault { a: 50, b: "overwritten".to_string() } => &[
Token::Struct { name: "StructDefault", len: 1 }, Token::Struct { name: "StructDefault", len: 2 },
Token::Str("a"), Token::Str("a"),
Token::I32(50), Token::I32(50),
@@ -623,7 +651,7 @@ declare_tests! {
Token::StructEnd, Token::StructEnd,
], ],
StructDefault { a: 100, b: "default".to_string() } => &[ StructDefault { a: 100, b: "default".to_string() } => &[
Token::Struct { name: "StructDefault", len: 0 }, Token::Struct { name: "StructDefault", len: 2 },
Token::StructEnd, Token::StructEnd,
], ],
} }
@@ -774,7 +802,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 +821,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 },
@@ -958,7 +988,7 @@ fn test_cstr_internal_null_end() {
declare_error_tests! { declare_error_tests! {
test_unknown_field<StructDenyUnknown> { test_unknown_field<StructDenyUnknown> {
&[ &[
Token::Struct { name: "StructDenyUnknown", len: 2 }, Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("a"), Token::Str("a"),
Token::I32(0), Token::I32(0),
@@ -968,14 +998,14 @@ declare_error_tests! {
} }
test_skipped_field_is_unknown<StructDenyUnknown> { test_skipped_field_is_unknown<StructDenyUnknown> {
&[ &[
Token::Struct { name: "StructDenyUnknown", len: 2 }, Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("b"), Token::Str("b"),
], ],
"unknown field `b`, expected `a`", "unknown field `b`, expected `a`",
} }
test_skip_all_deny_unknown<StructSkipAllDenyUnknown> { test_skip_all_deny_unknown<StructSkipAllDenyUnknown> {
&[ &[
Token::Struct { name: "StructSkipAllDenyUnknown", len: 1 }, Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
Token::Str("a"), Token::Str("a"),
], ],
"unknown field `a`, there are no fields", "unknown field `a`, there are no fields",
@@ -1180,7 +1210,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",
} }
+86 -67
View File
@@ -11,13 +11,8 @@
// types involved. // types involved.
#![deny(warnings)] #![deny(warnings)]
#![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;
@@ -27,6 +22,7 @@ use self::serde::de::{DeserializeOwned, Deserializer};
use std::borrow::Cow; use std::borrow::Cow;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::option::Option as StdOption;
use std::result::Result as StdResult; use std::result::Result as StdResult;
// Try to trip up the generated code if it fails to use fully qualified paths. // Try to trip up the generated code if it fails to use fully qualified paths.
@@ -36,6 +32,12 @@ struct Result;
struct Ok; struct Ok;
#[allow(dead_code)] #[allow(dead_code)]
struct Err; struct Err;
#[allow(dead_code)]
struct Option;
#[allow(dead_code)]
struct Some;
#[allow(dead_code)]
struct None;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -44,7 +46,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct With<T> { struct With<T> {
t: T, t: T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X, x: X,
} }
assert::<With<i32>>(); assert::<With<i32>>();
@@ -52,7 +54,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct WithTogether<T> { struct WithTogether<T> {
t: T, t: T,
#[serde(with="both_x")] #[serde(with = "both_x")]
x: X, x: X,
} }
assert::<WithTogether<i32>>(); assert::<WithTogether<i32>>();
@@ -60,8 +62,8 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct WithRef<'a, T: 'a> { struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
t: Option<&'a T>, t: StdOption<&'a T>,
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X, x: X,
} }
assert::<WithRef<i32>>(); assert::<WithRef<i32>>();
@@ -81,9 +83,9 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct NoBounds<T> { struct NoBounds<T> {
t: T, t: T,
option: Option<T>, option: StdOption<T>,
boxed: Box<T>, boxed: Box<T>,
option_boxed: Option<Box<T>>, option_boxed: StdOption<Box<T>>,
} }
assert::<NoBounds<i32>>(); assert::<NoBounds<i32>>();
@@ -91,17 +93,17 @@ fn test_gen() {
enum EnumWith<T> { enum EnumWith<T> {
Unit, Unit,
Newtype( Newtype(
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X X,
), ),
Tuple( Tuple(
T, T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X X,
), ),
Struct { Struct {
t: T, t: T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X, x: X,
}, },
} }
@@ -121,16 +123,16 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Newtype( struct Newtype(
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X X,
); );
assert::<Newtype>(); assert::<Newtype>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Tuple<T>( struct Tuple<T>(
T, T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")] #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X X,
); );
assert::<Tuple<i32>>(); assert::<Tuple<i32>>();
@@ -140,7 +142,9 @@ fn test_gen() {
left: Box<TreeNode<D>>, left: Box<TreeNode<D>>,
right: Box<TreeNode<D>>, right: Box<TreeNode<D>>,
}, },
Leaf { data: D }, Leaf {
data: D,
},
} }
assert::<TreeNode<i32>>(); assert::<TreeNode<i32>>();
@@ -179,35 +183,34 @@ fn test_gen() {
#[derive(Serialize)] #[derive(Serialize)]
struct OptionStatic<'a> { struct OptionStatic<'a> {
a: Option<&'a str>, a: StdOption<&'a str>,
b: Option<&'static str>, b: StdOption<&'static str>,
} }
assert_ser::<OptionStatic>(); assert_ser::<OptionStatic>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(bound="D: SerializeWith + DeserializeWith")] #[serde(bound = "D: SerializeWith + DeserializeWith")]
struct WithTraits1<D, E> { struct WithTraits1<D, E> {
#[serde(serialize_with="SerializeWith::serialize_with", #[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with")] deserialize_with = "DeserializeWith::deserialize_with")]
d: D, d: D,
#[serde(serialize_with="SerializeWith::serialize_with", #[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with", deserialize_with = "DeserializeWith::deserialize_with",
bound="E: SerializeWith + DeserializeWith")] bound = "E: SerializeWith + DeserializeWith")]
e: E, e: E,
} }
assert::<WithTraits1<X, X>>(); assert::<WithTraits1<X, X>>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(bound(serialize="D: SerializeWith", #[serde(bound(serialize = "D: SerializeWith", deserialize = "D: DeserializeWith"))]
deserialize="D: DeserializeWith"))]
struct WithTraits2<D, E> { struct WithTraits2<D, E> {
#[serde(serialize_with="SerializeWith::serialize_with", #[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with")] deserialize_with = "DeserializeWith::deserialize_with")]
d: D, d: D,
#[serde(serialize_with="SerializeWith::serialize_with", #[serde(serialize_with = "SerializeWith::serialize_with",
bound(serialize="E: SerializeWith"))] bound(serialize = "E: SerializeWith"))]
#[serde(deserialize_with="DeserializeWith::deserialize_with", #[serde(deserialize_with = "DeserializeWith::deserialize_with",
bound(deserialize="E: DeserializeWith"))] bound(deserialize = "E: DeserializeWith"))]
e: E, e: E,
} }
assert::<WithTraits2<X, X>>(); assert::<WithTraits2<X, X>>();
@@ -269,14 +272,14 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct TupleSkipAll( struct TupleSkipAll(
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
u8 u8,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown( struct TupleSkipAllDenyUnknown(
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
u8 u8,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -304,7 +307,7 @@ fn test_gen() {
}, },
TupleSkip( TupleSkip(
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
u8 u8,
), ),
} }
@@ -320,7 +323,7 @@ fn test_gen() {
}, },
TupleSkip( TupleSkip(
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
u8 u8,
), ),
} }
@@ -361,6 +364,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;
@@ -394,10 +403,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
Struct { Struct { f1: String, f2: u8 },
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")] #[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -420,10 +426,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
Struct { Struct { f1: String, f2: u8 },
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")] #[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -451,10 +454,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
Struct { Struct { f1: String, f2: u8 },
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")] #[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -482,10 +482,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
Struct { Struct { f1: String, f2: u8 },
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")] #[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")] #[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -508,13 +505,29 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> { enum StaticStrEnum<'a> {
Struct { Struct { a: &'a str, b: &'static str },
a: &'a str,
b: &'static str,
},
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>>();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -542,7 +555,7 @@ pub fn de_x<'de, D: Deserializer<'de>>(_: D) -> StdResult<X, D::Error> {
} }
mod both_x { mod both_x {
pub use super::{ser_x as serialize, de_x as deserialize}; pub use super::{de_x as deserialize, ser_x as serialize};
} }
impl SerializeWith for X { impl SerializeWith for X {
@@ -558,27 +571,33 @@ impl DeserializeWith for X {
} }
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error> pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
where S: Serializer, where
S: Serializer,
{ {
unimplemented!() unimplemented!()
} }
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error> pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
where D: Deserializer<'de>, where
D: Deserializer<'de>,
{ {
unimplemented!() unimplemented!()
} }
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error> pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
where S: Serializer, where
S: Serializer,
{ {
unimplemented!() unimplemented!()
} }
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error> pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
where D: Deserializer<'de>, where
D: Deserializer<'de>,
{ {
unimplemented!() unimplemented!()
} }
pub fn is_zero(n: &u8) -> bool { *n == 0 } pub fn is_zero(n: &u8) -> bool {
*n == 0
}
+1 -3
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() {
File diff suppressed because it is too large Load Diff
+7 -9
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;
@@ -123,7 +121,7 @@ struct UnitDef;
#[serde(remote = "remote::PrimitivePriv")] #[serde(remote = "remote::PrimitivePriv")]
struct PrimitivePrivDef( struct PrimitivePrivDef(
#[serde(getter = "remote::PrimitivePriv::get")] #[serde(getter = "remote::PrimitivePriv::get")]
u8 u8,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -134,14 +132,14 @@ struct PrimitivePubDef(u8);
#[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")] #[serde(with = "UnitDef")]
remote::Unit remote::Unit,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -150,7 +148,7 @@ struct TuplePrivDef(
#[serde(getter = "remote::TuplePriv::first")] #[serde(getter = "remote::TuplePriv::first")]
u8, u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] #[serde(getter = "remote::TuplePriv::second", with = "UnitDef")]
remote::Unit remote::Unit,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -158,7 +156,7 @@ struct TuplePrivDef(
struct TuplePubDef( struct TuplePubDef(
u8, u8,
#[serde(with = "UnitDef")] #[serde(with = "UnitDef")]
remote::Unit remote::Unit,
); );
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -168,7 +166,7 @@ struct StructPrivDef {
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,
} }
@@ -179,7 +177,7 @@ struct StructPubDef {
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),
); );
} }
+16 -15
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;
@@ -53,7 +50,10 @@ enum Enum {
Unit, Unit,
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)] #[serde(skip_serializing)]
@@ -61,21 +61,24 @@ enum Enum {
#[serde(skip_serializing)] #[serde(skip_serializing)]
SkippedSeq(i32, i32), SkippedSeq(i32, i32),
#[serde(skip_serializing)] #[serde(skip_serializing)]
SkippedMap { _a: i32, _b: i32 }, 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 +411,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 +430,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 +529,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