Compare commits

...

93 Commits

Author SHA1 Message Date
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
David Tolnay ad680cbd44 Release 1.0.17 2017-10-31 09:36:06 -07:00
David Tolnay ff0cfb1f1f Clean up trailing whitespace and where-clauses 2017-10-31 09:36:05 -07:00
David Tolnay 9b08915a18 Add tests for std::num::Wrapping impls 2017-10-31 09:32:58 -07:00
David Tolnay 501aa3ee1d Share the import of std::num::Wrapping 2017-10-31 09:27:58 -07:00
David Tolnay eebf0f8db8 Merge pull request #1072 from LinearZoetrope/wrapping
Add std::num::Wrapping impl
2017-10-31 09:26:17 -07:00
Zoe Juozapaitis a7e4911ddb Add newlines to ends of files 2017-10-31 04:29:00 -07:00
Zoe Juozapaitis eb08f037f5 Add std::num::Wrapping support 2017-10-31 03:02:58 -07:00
David Tolnay aa03fd5d1a Duplicate error messages have been fixed 2017-10-27 21:08:41 -04:00
David Tolnay e198afb0c1 Add missing copyright notices 2017-10-22 16:01:19 -07:00
David Tolnay bc8de251cf Update contributing.md with steps for running test suite 2017-10-22 15:46:54 -07:00
David Tolnay 99e8686189 Add error banner when running test suite without nightly compiler 2017-10-22 15:46:17 -07:00
David Tolnay 826f656e28 Compile and test the serde_derive "example" code 2017-10-22 12:09:56 -07:00
David Tolnay ab7c003b64 Remove associated constants workaround
This has been stable since Rust 1.20.
2017-10-22 11:55:16 -07:00
David Tolnay 422191fcb0 Release 1.0.16 2017-10-22 11:29:44 -07:00
David Tolnay 4ba748c902 Clean up trailing whitespace 2017-10-22 11:29:35 -07:00
David Tolnay 14ed6f2dab Simplify some IntoDeserializer deserializer types 2017-10-20 21:38:18 -07:00
David Tolnay 30606a43aa IntoDeserializer for HashSet and HashMap with non-default hasher 2017-10-20 21:36:40 -07:00
David Tolnay 9be3d32016 Remove redundant readable/compact tests
This functionality is covered well enough by the std::net types.
2017-10-17 23:16:21 -07:00
David Tolnay 5daf1b89a1 Consolidate readable/compact deserialization tests 2017-10-17 23:15:35 -07:00
David Tolnay f8f5d0ca2f No need for readable setting for the ignore test 2017-10-17 23:09:50 -07:00
David Tolnay 57873cce28 Remove unused deserialization macros on no_std 2017-10-17 10:04:26 -07:00
David Tolnay 4ed0362c8e Panic by default in serde_test is_human_readable
The serde_test Serializer and Deserializer panic in is_human_readable unless the
readableness has been set explicitly through one of the hidden functions. This
is to force types that have distinct readable/compact representations to be
tested explicitly in one or the other, rather than with a plain assert_tokens
which arbitrarily picks one.

We need to follow up by designing a better API in serde_test to expose this
publicly. For now serde_test cannot be used to test types that rely on
is_human_readable. (The hidden functions are meant for our test suite only.)
2017-10-17 09:49:42 -07:00
David Tolnay 4cecaf8d02 Test the maximum std::net string lengths 2017-10-15 20:32:30 -07:00
David Tolnay 50c696aabe Write is_human_readable examples 2017-10-15 20:27:03 -07:00
David Tolnay 2f58a20bc6 Inline is_human_readable 2017-10-15 16:54:48 -07:00
David Tolnay 030459a040 Merge pull request #1044 from Marwes/human_readable
Serialize to binary if the serde format is not human readable
2017-10-15 16:39:58 -07:00
Markus Westerlind e9b530a000 Hide is_human_readable constructors in serde_test
Until a good API can be found
2017-10-13 17:37:47 +02:00
David Tolnay ea1a729088 Release 1.0.15 2017-09-17 13:58:35 -07:00
David Tolnay 857dcea774 Merge pull request #1058 from serde-rs/internally-tagged-seq
Support deserializing internally tagged enum from seq
2017-09-17 13:57:33 -07:00
David Tolnay b98a9a8f9b Support deserializing internally tagged enum from seq
During serialization, internally tagged enums invoke the Serializer's
serialize_struct. In JSON this turns into a map which uses visit_map
when deserialized. But some formats employ visit_seq when
deserializing a struct. One example is rmp-serde. Such formats were
previously unable to deserialize an internally tagged enum. This
change fixes it by adding visit_seq for internally tagged enums.
2017-09-17 13:45:12 -07:00
Markus Westerlind 3b135431fd Try to fix compilation on 1.13 2017-09-14 17:12:23 +02:00
Markus Westerlind 945d12c0b4 Use the variant_identifier macro for OsString 2017-09-14 17:08:17 +02:00
Markus Westerlind e36915300f Properly deserialize non-readable IpAddr and SocketAddr 2017-09-14 17:08:17 +02:00
Markus Westerlind 85c05d301a Fix the non-readble IpAddr serialize implementations 2017-09-11 17:40:02 +02:00
Markus Westerlind c2474bf6ee Document that is_human_readable == false is a breaking change 2017-09-11 17:18:35 +02:00
Markus Westerlind a52f436788 Fix rustc 1.13 and clippy errors on travis 2017-09-11 16:03:00 +02:00
Markus Westerlind ad3335e5d6 Serialize non-human-readble ip addresses as tuples
Since we know exactly how many bytes we should serialize as we can hint
to the serializer that it is not required which further reduces the
serialized size when compared to just serializing as bytes.
2017-09-11 15:54:53 +02:00
David Tolnay 4b00de0e22 Release 1.0.14 2017-09-09 12:50:57 -07:00
David Tolnay 8403fa018e Merge pull request #1052 from serde-rs/static
Special case for 'static fields
2017-09-09 12:50:11 -07:00
David Tolnay 0e9f1b42de Merge pull request #1053 from serde-rs/cast
Fix trivial numeric cast in visit_u64
2017-09-09 12:43:46 -07:00
David Tolnay 0085d05e55 Special case for 'static fields 2017-09-09 12:39:14 -07:00
David Tolnay 2eed855bff Fix trivial numeric cast in visit_u64 2017-09-09 12:37:00 -07:00
Markus Westerlind 40c670e625 Add non-human readable serializations for ip addresses 2017-09-08 10:37:33 +02:00
Markus Westerlind 0dccbb1f11 Serialize to binary if the serde format is not human readable
This implements the KISS suggested in https://github.com/serde-rs/serde/issues/790.
It is possible that one of the other approaches may be better but this
seemed like the simplest one to reignite som discussion.

Personally I find the original suggestion of adding two traits perhaps slightly
cleaner in theory but I think it ends up more complicated in the end
since the added traits also need to be duplicated to to the `Seed`
traits.

Closes #790
2017-09-07 16:20:57 +02:00
44 changed files with 2126 additions and 494 deletions
+52 -31
View File
@@ -1,45 +1,66 @@
# Contributing to Serde
Serde welcomes contribution from everyone. Here are the guidelines if you are
thinking of helping us:
Serde welcomes contribution from everyone in the form of suggestions, bug
reports, pull requests, and feedback. This document gives some guidance if you
are thinking of helping us.
## Contributions
Please reach out here in a GitHub issue or in the #serde IRC channel on
[`irc.mozilla.org`] if we can do anything to help you contribute.
Contributions to Serde or its dependencies should be made in the form of GitHub
pull requests. Each pull request will be reviewed by a core contributor
(someone with permission to land patches) and either landed in the main tree or
given feedback for changes that would be required. All contributions should
follow this format, even those from core contributors.
[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
Should you wish to work on an issue, please claim it first by commenting on
the GitHub issue that you want to work on it. This is to prevent duplicated
efforts from contributors on the same issue.
## Submitting bug reports and feature requests
## Pull Request Checklist
Serde development is spread across lots of repositories, but this serde-rs/serde
repository is always a safe choice for opening any issues related to Serde.
- Branch from the master branch and, if needed, rebase to the current master
branch before submitting your pull request. If it doesn't merge cleanly with
master you may be asked to rebase your changes.
When reporting a bug or asking for help, please include enough details so that
the people helping you can reproduce the behavior you are seeing. For some tips
on how to approach this, read about how to produce a [Minimal, Complete, and
Verifiable example].
- Commits should be as small as possible, while ensuring that each commit is
correct independently (i.e., each commit should compile and pass tests).
[Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve
- If your patch is not getting reviewed or you need a specific person to review
it, you can @-reply a reviewer asking for a review in the pull request or a
comment, or you can ask for a review in `#serde` on `irc.mozilla.org`.
When making a feature request, please make it clear what problem you intend to
solve with the feature, any ideas for how Serde could support solving that
problem, any possible alternatives, and any disadvantages.
- Add tests relevant to the fixed bug or new feature.
## Running the test suite
We encourage you to check that the test suite passes locally before submitting a
pull request with your changes. If anything does not pass, typically it will be
easier to iterate and fix it locally than waiting for the CI servers to run
tests for you.
##### In the [`serde`] directory
```sh
# Test all the example code in Serde documentation
cargo test
```
##### In the [`test_suite/deps`] directory
```sh
# This is a prerequisite for running the full test suite
cargo clean && cargo update && cargo build
```
##### In the [`test_suite`] directory
```sh
# Run the full test suite, including tests of unstable functionality
cargo test --features unstable
```
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
[`test_suite/deps`]: https://github.com/serde-rs/serde/tree/master/test_suite/deps
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
## Conduct
In all Serde-related forums, we follow the [Rust Code of
Conduct](https://www.rust-lang.org/conduct.html). For escalation or moderation
issues, please contact Erick (erick.tryzelaar@gmail.com) instead of the Rust
moderation team.
In all Serde-related forums, we follow the [Rust Code of Conduct]. For
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
instead of the Rust moderation team.
## Communication
Beyond opening tickets on the
[serde-rs/serde](https://github.com/serde-rs/serde) project, Serde contributors
frequent the `#serde` channel on
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC).
[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html
+24 -3
View File
@@ -20,9 +20,30 @@ You may be looking for:
## Serde in action
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
</a>
<details>
<summary>
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
#[macro_use]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.13" # remember to update html_root_url
version = "1.0.23" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
+198 -74
View File
@@ -869,37 +869,206 @@ map_impl!(
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
macro_rules! parse_impl {
($ty:ty) => {
macro_rules! parse_ip_impl {
($ty:ty; $size: expr) => {
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
if deserializer.is_human_readable() {
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
} else {
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
}
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::IpAddr);
macro_rules! variant_identifier {
(
$name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
$expecting_message: expr,
$variants_name: ident
) => {
enum $name_kind {
$( $variant ),*
}
static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*];
impl<'de> Deserialize<'de> for $name_kind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct KindVisitor;
impl<'de> Visitor<'de> for KindVisitor {
type Value = $name_kind;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str($expecting_message)
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
$index => Ok($name_kind :: $variant),
)*
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
stringify!($variant) => Ok($name_kind :: $variant),
)*
_ => Err(Error::unknown_variant(value, $variants_name)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
$bytes => Ok($name_kind :: $variant),
)*
_ => {
match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, $variants_name)),
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
}
}
}
}
}
deserializer.deserialize_identifier(KindVisitor)
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::Ipv4Addr);
macro_rules! deserialize_enum {
(
$name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
$expecting_message: expr,
$deserializer: expr
) => {
variant_identifier!{
$name_kind ( $($variant; $bytes; $index),* )
$expecting_message,
VARIANTS
}
struct EnumVisitor;
impl<'de> Visitor<'de> for EnumVisitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a ", stringify!($name)))
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
match try!(data.variant()) {
$(
($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant),
)*
}
}
}
$deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor)
}
}
#[cfg(feature = "std")]
parse_impl!(net::Ipv6Addr);
impl<'de> Deserialize<'de> for net::IpAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
} else {
use lib::net::IpAddr;
deserialize_enum!{
IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::SocketAddr);
parse_ip_impl!(net::Ipv4Addr; 4);
#[cfg(feature = "std")]
parse_impl!(net::SocketAddrV4);
parse_ip_impl!(net::Ipv6Addr; 16);
#[cfg(feature = "std")]
parse_impl!(net::SocketAddrV6);
macro_rules! parse_socket_impl {
($ty:ty, $new: expr) => {
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
} else {
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
}
}
}
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for net::SocketAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
} else {
use lib::net::SocketAddr;
deserialize_enum!{
SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
}
}
}
}
#[cfg(feature = "std")]
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
#[cfg(feature = "std")]
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0));
////////////////////////////////////////////////////////////////////////////////
@@ -984,70 +1153,10 @@ impl<'de> Deserialize<'de> for PathBuf {
// #[derive(Deserialize)]
// #[serde(variant_identifier)]
#[cfg(all(feature = "std", any(unix, windows)))]
enum OsStringKind {
Unix,
Windows,
}
#[cfg(all(feature = "std", any(unix, windows)))]
static OSSTR_VARIANTS: &'static [&'static str] = &["Unix", "Windows"];
#[cfg(all(feature = "std", any(unix, windows)))]
impl<'de> Deserialize<'de> for OsStringKind {
fn deserialize<D>(deserializer: D) -> Result<OsStringKind, D::Error>
where
D: Deserializer<'de>,
{
struct KindVisitor;
impl<'de> Visitor<'de> for KindVisitor {
type Value = OsStringKind;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`Unix` or `Windows`")
}
fn visit_u32<E>(self, value: u32) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
0 => Ok(OsStringKind::Unix),
1 => Ok(OsStringKind::Windows),
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
}
}
fn visit_str<E>(self, value: &str) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
"Unix" => Ok(OsStringKind::Unix),
"Windows" => Ok(OsStringKind::Windows),
_ => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
b"Unix" => Ok(OsStringKind::Unix),
b"Windows" => Ok(OsStringKind::Windows),
_ => {
match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
}
}
}
}
}
deserializer.deserialize_identifier(KindVisitor)
}
variant_identifier!{
OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1)
"`Unix` or `Windows`",
OSSTR_VARIANTS
}
#[cfg(all(feature = "std", any(unix, windows)))]
@@ -1716,3 +1825,18 @@ where
deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData))
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl<'de, T> Deserialize<'de> for Wrapping<T>
where
T: Deserialize<'de>
{
fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Wrapping)
}
}
+68
View File
@@ -1011,6 +1011,74 @@ pub trait Deserializer<'de>: Sized {
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
/// Determine whether `Deserialize` implementations should expect to
/// deserialize their human-readable form.
///
/// Some types have a human-readable form that may be somewhat expensive to
/// construct, as well as a binary form that is compact and efficient.
/// Generally text-based formats like JSON and YAML will prefer to use the
/// human-readable one and binary formats like Bincode will prefer the
/// compact one.
///
/// ```
/// # use std::ops::Add;
/// # use std::str::FromStr;
/// #
/// # struct Timestamp;
/// #
/// # impl Timestamp {
/// # const EPOCH: Timestamp = Timestamp;
/// # }
/// #
/// # impl FromStr for Timestamp {
/// # type Err = String;
/// # fn from_str(_: &str) -> Result<Self, Self::Err> {
/// # unimplemented!()
/// # }
/// # }
/// #
/// # struct Duration;
/// #
/// # impl Duration {
/// # fn seconds(_: u64) -> Self { unimplemented!() }
/// # }
/// #
/// # impl Add<Duration> for Timestamp {
/// # type Output = Timestamp;
/// # fn add(self, _: Duration) -> Self::Output {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::de::{self, Deserialize, Deserializer};
///
/// impl<'de> Deserialize<'de> for Timestamp {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de>
/// {
/// if deserializer.is_human_readable() {
/// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z".
/// let s = String::deserialize(deserializer)?;
/// Timestamp::from_str(&s).map_err(de::Error::custom)
/// } else {
/// // Deserialize from a compact binary representation, seconds since
/// // the Unix epoch.
/// let n = u64::deserialize(deserializer)?;
/// Ok(Timestamp::EPOCH + Duration::seconds(n))
/// }
/// }
/// }
/// ```
///
/// The default implementation of this method returns `true`. Data formats
/// may override this to `false` to request a compact form for types that
/// support one. Note that modifying this method to change a format from
/// human-readable to compact or vice versa should be regarded as a breaking
/// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode.
#[inline]
fn is_human_readable(&self) -> bool { true }
}
////////////////////////////////////////////////////////////////////////////////
+9 -7
View File
@@ -733,7 +733,7 @@ where
T: IntoDeserializer<'de, E>,
E: de::Error,
{
type Deserializer = SeqDeserializer<<Vec<T> as IntoIterator>::IntoIter, E>;
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
fn into_deserializer(self) -> Self::Deserializer {
SeqDeserializer::new(self.into_iter())
@@ -746,7 +746,7 @@ where
T: IntoDeserializer<'de, E> + Eq + Ord,
E: de::Error,
{
type Deserializer = SeqDeserializer<<BTreeSet<T> as IntoIterator>::IntoIter, E>;
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
fn into_deserializer(self) -> Self::Deserializer {
SeqDeserializer::new(self.into_iter())
@@ -754,12 +754,13 @@ where
}
#[cfg(feature = "std")]
impl<'de, T, E> IntoDeserializer<'de, E> for HashSet<T>
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
where
T: IntoDeserializer<'de, E> + Eq + Hash,
S: BuildHasher,
E: de::Error,
{
type Deserializer = SeqDeserializer<<HashSet<T> as IntoIterator>::IntoIter, E>;
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
fn into_deserializer(self) -> Self::Deserializer {
SeqDeserializer::new(self.into_iter())
@@ -1152,7 +1153,7 @@ where
V: IntoDeserializer<'de, E>,
E: de::Error,
{
type Deserializer = MapDeserializer<'de, <BTreeMap<K, V> as IntoIterator>::IntoIter, E>;
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
fn into_deserializer(self) -> Self::Deserializer {
MapDeserializer::new(self.into_iter())
@@ -1160,13 +1161,14 @@ where
}
#[cfg(feature = "std")]
impl<'de, K, V, E> IntoDeserializer<'de, E> for HashMap<K, V>
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
where
K: IntoDeserializer<'de, E> + Eq + Hash,
V: IntoDeserializer<'de, E>,
S: BuildHasher,
E: de::Error,
{
type Deserializer = MapDeserializer<'de, <HashMap<K, V> as IntoIterator>::IntoIter, E>;
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
fn into_deserializer(self) -> Self::Deserializer {
MapDeserializer::new(self.into_iter())
+5 -1
View File
@@ -79,7 +79,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.13")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.23")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
@@ -95,8 +95,10 @@
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(
cast_lossless,
const_static_lifetime,
doc_markdown,
linkedlist,
needless_pass_by_value,
type_complexity,
unreadable_literal,
zero_prefixed_literal,
@@ -207,6 +209,8 @@ mod lib {
#[cfg(feature = "std")]
pub use std::io::Write;
#[cfg(feature = "std")]
pub use std::num::Wrapping;
#[cfg(feature = "std")]
pub use std::path::{Path, PathBuf};
#[cfg(feature = "std")]
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
+69 -11
View File
@@ -834,26 +834,43 @@ mod content {
type Value = TaggedContent<'de, T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
fmt.write_str("internally tagged enum")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
V: MapAccess<'de>,
S: SeqAccess<'de>,
{
let tag = match try!(seq.next_element()) {
Some(tag) => tag,
None => {
return Err(de::Error::missing_field(self.tag_name));
}
};
let rest = de::value::SeqAccessDeserializer::new(seq);
Ok(TaggedContent {
tag: tag,
content: try!(Content::deserialize(rest)),
})
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut tag = None;
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
while let Some(k) =
try!(visitor.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k {
TagOrContent::Tag => {
if tag.is_some() {
return Err(de::Error::duplicate_field(self.tag_name));
}
tag = Some(try!(visitor.next_value()));
tag = Some(try!(map.next_value()));
}
TagOrContent::Content(k) => {
let v = try!(visitor.next_value());
let v = try!(map.next_value());
vec.push((k, v));
}
}
@@ -1097,10 +1114,38 @@ mod content {
)
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
// As a special case, allow deserializing untagged newtype
// variant containing unit struct.
//
// #[derive(Deserialize)]
// struct Info;
//
// #[derive(Deserialize)]
// #[serde(tag = "topic")]
// enum Message {
// Info(Info),
// }
//
// We want {"topic":"Info"} to deserialize even though
// ordinarily unit structs do not deserialize from empty map.
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
_ => self.deserialize_any(visitor),
}
}
forward_to_deserialize_any! {
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
identifier ignored_any
byte_buf unit seq tuple tuple_struct map struct identifier
ignored_any
}
}
@@ -1201,6 +1246,9 @@ mod content {
Some(Content::Map(v)) => {
de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
}
Some(Content::Seq(v)) => {
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"),),
}
@@ -1595,6 +1643,9 @@ mod content {
Some(&Content::Map(ref v)) => {
de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
}
Some(&Content::Seq(ref v)) => {
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"),),
}
@@ -1802,9 +1853,16 @@ mod content {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
}
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
where
V: MapAccess<'de>,
S: SeqAccess<'de>,
{
Ok(())
}
fn visit_map<M>(self, _: M) -> Result<(), M::Error>
where
M: MapAccess<'de>,
{
Ok(())
}
+3 -3
View File
@@ -60,7 +60,6 @@ enum Unsupported {
ByteArray,
Optional,
Unit,
UnitStruct,
Sequence,
Tuple,
TupleStruct,
@@ -79,7 +78,6 @@ impl Display for Unsupported {
Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"),
Unsupported::Unit => formatter.write_str("unit"),
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
@@ -199,7 +197,9 @@ where
}
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
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(
+68 -18
View File
@@ -506,9 +506,18 @@ impl Serialize for net::IpAddr {
where
S: Serializer,
{
match *self {
net::IpAddr::V4(ref a) => a.serialize(serializer),
net::IpAddr::V6(ref a) => a.serialize(serializer),
if serializer.is_human_readable() {
match *self {
net::IpAddr::V4(ref a) => a.serialize(serializer),
net::IpAddr::V6(ref a) => a.serialize(serializer),
}
} else {
match *self {
net::IpAddr::V4(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a),
net::IpAddr::V6(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a),
}
}
}
}
@@ -519,9 +528,13 @@ impl Serialize for net::Ipv4Addr {
where
S: Serializer,
{
/// "101.102.103.104".len()
const MAX_LEN: usize = 15;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
if serializer.is_human_readable() {
const MAX_LEN: usize = 15;
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else {
self.octets().serialize(serializer)
}
}
}
@@ -531,9 +544,13 @@ impl Serialize for net::Ipv6Addr {
where
S: Serializer,
{
/// "1000:1002:1003:1004:1005:1006:1007:1008".len()
const MAX_LEN: usize = 39;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
if serializer.is_human_readable() {
const MAX_LEN: usize = 39;
debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len());
serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else {
self.octets().serialize(serializer)
}
}
}
@@ -543,9 +560,18 @@ impl Serialize for net::SocketAddr {
where
S: Serializer,
{
match *self {
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
if serializer.is_human_readable() {
match *self {
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
}
} else {
match *self {
net::SocketAddr::V4(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr),
net::SocketAddr::V6(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr),
}
}
}
}
@@ -556,9 +582,13 @@ impl Serialize for net::SocketAddrV4 {
where
S: Serializer,
{
/// "101.102.103.104:65000".len()
const MAX_LEN: usize = 21;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
if serializer.is_human_readable() {
const MAX_LEN: usize = 21;
debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len());
serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else {
(self.ip(), self.port()).serialize(serializer)
}
}
}
@@ -568,9 +598,13 @@ impl Serialize for net::SocketAddrV6 {
where
S: Serializer,
{
/// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len()
const MAX_LEN: usize = 47;
serialize_display_bounded_length!(self, MAX_LEN, serializer)
if serializer.is_human_readable() {
const MAX_LEN: usize = 47;
debug_assert_eq!(MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len());
serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else {
(self.ip(), self.port()).serialize(serializer)
}
}
}
@@ -630,3 +664,19 @@ impl Serialize for OsString {
self.as_os_str().serialize(serializer)
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl<T> Serialize for Wrapping<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
+50
View File
@@ -1363,6 +1363,56 @@ pub trait Serializer: Sized {
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display;
/// Determine whether `Serialize` implementations should serialize in
/// human-readable form.
///
/// Some types have a human-readable form that may be somewhat expensive to
/// construct, as well as a binary form that is compact and efficient.
/// Generally text-based formats like JSON and YAML will prefer to use the
/// human-readable one and binary formats like Bincode will prefer the
/// compact one.
///
/// ```
/// # use std::fmt::{self, Display};
/// #
/// # struct Timestamp;
/// #
/// # impl Timestamp {
/// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() }
/// # }
/// #
/// # impl Display for Timestamp {
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::{Serialize, Serializer};
///
/// impl Serialize for Timestamp {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer
/// {
/// if serializer.is_human_readable() {
/// // Serialize to a human-readable string "2015-05-15T17:01:00Z".
/// self.to_string().serialize(serializer)
/// } else {
/// // Serialize to a compact binary representation.
/// self.seconds_since_epoch().serialize(serializer)
/// }
/// }
/// }
/// ```
///
/// The default implementation of this method returns `true`. Data formats
/// may override this to `false` to request a compact form for types that
/// support one. Note that modifying this method to change a format from
/// human-readable to compact or vice versa should be regarded as a breaking
/// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode.
#[inline]
fn is_human_readable(&self) -> bool { true }
}
/// Returned from `Serializer::serialize_seq`.
+5 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.13" # remember to update html_root_url
version = "1.0.23" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -20,5 +20,8 @@ proc-macro = true
[dependencies]
quote = "0.3.8"
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
serde_derive_internals = { version = "=0.17.0", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] }
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
+9 -1
View File
@@ -15,7 +15,7 @@ use internals::attr;
macro_rules! path {
($($path:tt)+) => {
syn::parse_path(stringify!($($path)+)).unwrap()
syn::parse_path(quote!($($path)+).as_str()).unwrap()
};
}
@@ -116,6 +116,14 @@ where
}
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
+131 -67
View File
@@ -26,13 +26,14 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
let body = Stmts(deserialize_body(&cont, &params));
let delife = params.borrowed.de_lifetime();
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
quote! {
impl #de_impl_generics #ident #ty_generics #where_clause {
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
#body
}
@@ -41,9 +42,9 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
} else {
quote! {
#[automatically_derived]
impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause {
impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
#body
}
@@ -75,7 +76,7 @@ struct Parameters {
/// Lifetimes borrowed from the deserializer. These will become bounds on
/// the `'de` lifetime of the deserializer.
borrowed: BTreeSet<syn::Lifetime>,
borrowed: BorrowedLifetimes,
/// At least one field has a serde(getter) attribute, implying that the
/// remote type has a private field.
@@ -89,8 +90,8 @@ impl Parameters {
Some(remote) => remote.clone(),
None => cont.ident.clone().into(),
};
let generics = build_generics(cont);
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.body.has_getter();
Parameters {
@@ -107,20 +108,12 @@ impl Parameters {
fn type_name(&self) -> &str {
self.this.segments.last().unwrap().ident.as_ref()
}
fn de_lifetime_def(&self) -> syn::LifetimeDef {
syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de"),
bounds: self.borrowed.iter().cloned().collect(),
}
}
}
// All the generics in the input, plus a bound `T: Deserialize` for each generic
// field type that will be deserialized by us, plus a bound `T: Default` for
// each generic field type that will be set to a default value.
fn build_generics(cont: &Container) -> syn::Generics {
fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics {
let generics = bound::without_defaults(cont.generics);
let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound);
@@ -136,11 +129,12 @@ fn build_generics(cont: &Container) -> syn::Generics {
attr::Default::Path(_) => generics,
};
let delife = borrowed.de_lifetime();
let generics = bound::with_bound(
cont,
&generics,
needs_deserialize_bound,
&path!(_serde::Deserialize<'de>),
&path!(_serde::Deserialize<#delife>),
);
bound::with_bound(
@@ -170,18 +164,54 @@ fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bo
field.default() == &attr::Default::Default
}
enum BorrowedLifetimes {
Borrowed(BTreeSet<syn::Lifetime>),
Static,
}
impl BorrowedLifetimes {
fn de_lifetime(&self) -> syn::Lifetime {
match *self {
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"),
BorrowedLifetimes::Static => syn::Lifetime::new("'static"),
}
}
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
match *self {
BorrowedLifetimes::Borrowed(ref bounds) => {
Some(syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de"),
bounds: bounds.iter().cloned().collect(),
})
}
BorrowedLifetimes::Static => None,
}
}
}
// The union of lifetimes borrowed by each field of the container.
//
// These turn into bounds on the `'de` lifetime of the Deserialize impl. If
// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is:
//
// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c>
fn borrowed_lifetimes(cont: &Container) -> BTreeSet<syn::Lifetime> {
//
// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant
// and we use plain `'static` instead of `'de`.
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
let mut lifetimes = BTreeSet::new();
for field in cont.body.all_fields() {
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
if !field.attrs.skip_deserializing() {
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
}
}
if lifetimes.iter().any(|b| b.ident == "'static") {
BorrowedLifetimes::Static
} else {
BorrowedLifetimes::Borrowed(lifetimes)
}
lifetimes
}
fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
@@ -194,7 +224,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
deserialize_struct(None, params, fields, &cont.attrs, None)
deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No)
}
Body::Struct(Style::Tuple, ref fields) |
Body::Struct(Style::Newtype, ref fields) => {
@@ -260,6 +290,7 @@ fn deserialize_tuple(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
@@ -321,10 +352,10 @@ fn deserialize_tuple(
quote_block! {
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -335,7 +366,7 @@ fn deserialize_tuple(
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
where __A: _serde::de::SeqAccess<#delife>
{
#visit_seq
}
@@ -387,8 +418,8 @@ fn deserialize_seq(
};
let assign = quote! {
let #var = match #visit {
Some(__value) => __value,
None => {
_serde::export::Some(__value) => __value,
_serde::export::None => {
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
}
};
@@ -423,6 +454,8 @@ fn deserialize_seq(
}
fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens {
let delife = params.borrowed.de_lifetime();
let value = match field.attrs.deserialize_with() {
None => {
let field_ty = &field.ty;
@@ -450,25 +483,31 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
quote! {
#[inline]
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
where __E: _serde::Deserializer<'de>
where __E: _serde::Deserializer<#delife>
{
_serde::export::Ok(#result)
}
}
}
enum Untagged {
Yes,
No,
}
fn deserialize_struct(
variant_ident: Option<&syn::Ident>,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
deserializer: Option<Tokens>,
untagged: Untagged,
) -> Fragment {
let is_enum = variant_ident.is_some();
let is_untagged = deserializer.is_some();
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
@@ -527,18 +566,19 @@ fn deserialize_struct(
quote!(mut __seq)
};
let visit_seq = if is_untagged {
// untagged struct variants do not get a visit_seq method
None
} else {
Some(quote! {
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
{
#visit_seq
}
})
// untagged struct variants do not get a visit_seq method
let visit_seq = match untagged {
Untagged::Yes => None,
Untagged::No => {
Some(quote! {
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<#delife>
{
#visit_seq
}
})
}
};
quote_block! {
@@ -546,10 +586,10 @@ fn deserialize_struct(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -560,7 +600,7 @@ fn deserialize_struct(
#[inline]
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de>
where __A: _serde::de::MapAccess<#delife>
{
#visit_map
}
@@ -597,6 +637,7 @@ fn deserialize_externally_tagged_enum(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let type_name = cattrs.name().deserialize_name();
@@ -662,10 +703,10 @@ fn deserialize_externally_tagged_enum(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -673,7 +714,7 @@ fn deserialize_externally_tagged_enum(
}
fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::EnumAccess<'de>
where __A: _serde::de::EnumAccess<#delife>
{
#match_variant
}
@@ -754,6 +795,7 @@ fn deserialize_adjacently_tagged_enum(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let variant_names_idents: Vec<_> = variants
.iter()
@@ -913,14 +955,14 @@ fn deserialize_adjacently_tagged_enum(
struct __Seed #de_impl_generics #where_clause {
field: __Field,
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::DeserializeSeed<'de> for __Seed #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result<Self::Value, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
match self.field {
#(#variant_arms)*
@@ -930,10 +972,10 @@ fn deserialize_adjacently_tagged_enum(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -941,7 +983,7 @@ fn deserialize_adjacently_tagged_enum(
}
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de>
where __A: _serde::de::MapAccess<#delife>
{
// Visit the first relevant key.
match #next_relevant_key {
@@ -1005,7 +1047,7 @@ fn deserialize_adjacently_tagged_enum(
}
fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
where __A: _serde::de::SeqAccess<#delife>
{
// Visit the first element - the tag.
match try!(_serde::de::SeqAccess::next_element(&mut __seq)) {
@@ -1114,7 +1156,7 @@ fn deserialize_externally_tagged_variant(
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
}
Style::Struct => {
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None)
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None, Untagged::No)
}
}
}
@@ -1141,8 +1183,23 @@ fn deserialize_internally_tagged_variant(
_serde::export::Ok(#this::#variant_ident)
}
}
Style::Newtype | Style::Struct => {
deserialize_untagged_variant(params, variant, cattrs, deserializer)
Style::Newtype => {
deserialize_untagged_newtype_variant(
variant_ident,
params,
&variant.fields[0],
deserializer,
)
}
Style::Struct => {
deserialize_struct(
Some(variant_ident),
params,
&variant.fields,
cattrs,
Some(deserializer),
Untagged::No,
)
}
Style::Tuple => unreachable!("checked in serde_derive_internals"),
}
@@ -1204,6 +1261,7 @@ fn deserialize_untagged_variant(
&variant.fields,
cattrs,
Some(deserializer),
Untagged::Yes,
)
}
}
@@ -1366,6 +1424,7 @@ fn deserialize_custom_identifier(
};
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let visitor_impl =
Stmts(deserialize_identifier(this.clone(), &names_idents, is_variant, fallthrough),);
@@ -1374,10 +1433,10 @@ fn deserialize_custom_identifier(
struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __FieldVisitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
#visitor_impl
@@ -1428,7 +1487,7 @@ fn deserialize_identifier(
#variant_indices => _serde::export::Ok(#constructors),
)*
_ => _serde::export::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value as u64),
_serde::de::Unexpected::Unsigned(__value),
&#fallthrough_msg))
}
}
@@ -1694,17 +1753,18 @@ fn wrap_deserialize_with(
) -> (Tokens, Tokens) {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let wrapper = quote! {
struct __DeserializeWith #de_impl_generics #where_clause {
value: #value_ty,
phantom: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::Deserialize<'de> for __DeserializeWith #de_ty_generics #where_clause {
impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
_serde::export::Ok(__DeserializeWith {
value: try!(#deserialize_with(__deserializer)),
@@ -1822,20 +1882,24 @@ struct DeImplGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone();
generics.lifetimes.insert(0, self.0.de_lifetime_def());
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
generics.lifetimes.insert(0, de_lifetime);
}
let (impl_generics, _, _) = generics.split_for_impl();
impl_generics.to_tokens(tokens);
}
}
struct DeTyGenerics<'a>(&'a syn::Generics);
struct DeTyGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeTyGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.clone();
generics
.lifetimes
.insert(0, syn::LifetimeDef::new("'de"));
let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() {
generics
.lifetimes
.insert(0, syn::LifetimeDef::new("'de"));
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
@@ -1844,7 +1908,7 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
fn split_with_de_lifetime(params: &Parameters,)
-> (DeImplGenerics, DeTyGenerics, syn::TyGenerics, &syn::WhereClause) {
let de_impl_generics = DeImplGenerics(&params);
let de_ty_generics = DeTyGenerics(&params.generics);
let de_ty_generics = DeTyGenerics(&params);
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
(de_impl_generics, de_ty_generics, ty_generics, where_clause)
}
+8 -2
View File
@@ -8,15 +8,21 @@
//! This crate provides Serde's two derive macros.
//!
//! ```rust,ignore
//! ```rust
//! # #[macro_use]
//! # extern crate serde_derive;
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.13")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.23")]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.16.0" # remember to update html_root_url
version = "0.17.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
+10 -9
View File
@@ -51,7 +51,7 @@ impl<'a> Container<'a> {
let mut body = match item.body {
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
syn::Body::Struct(ref variant_data) => {
let (style, fields) = struct_from_ast(cx, variant_data);
let (style, fields) = struct_from_ast(cx, variant_data, None);
Body::Struct(style, fields)
}
};
@@ -103,10 +103,11 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
.iter()
.map(
|variant| {
let (style, fields) = struct_from_ast(cx, &variant.data);
let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
Variant {
ident: variant.ident.clone(),
attrs: attr::Variant::from_ast(cx, variant),
attrs: attrs,
style: style,
fields: fields,
}
@@ -115,18 +116,18 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
.collect()
}
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) {
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
match *data {
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)),
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
(Style::Newtype, fields_from_ast(cx, fields))
(Style::Newtype, fields_from_ast(cx, fields, attrs))
}
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)),
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Unit => (Style::Unit, Vec::new()),
}
}
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
fields
.iter()
.enumerate()
@@ -134,7 +135,7 @@ fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|(i, field)| {
Field {
ident: field.ident.clone(),
attrs: attr::Field::from_ast(cx, i, field),
attrs: attr::Field::from_ast(cx, i, field, attrs),
ty: &field.ty,
}
},
+23 -2
View File
@@ -512,6 +512,7 @@ pub struct Variant {
other: bool,
serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>,
borrow: Option<syn::MetaItem>,
}
impl Variant {
@@ -524,6 +525,7 @@ impl Variant {
let mut other = BoolAttr::none(cx, "other");
let mut serialize_with = Attr::none(cx, "serialize_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_item in meta_items {
@@ -599,6 +601,18 @@ impl Variant {
}
}
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
MetaItem(ref mi) if mi.name() == "borrow" => {
match variant.data {
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
borrow.set(mi.clone());
}
_ => {
cx.error("#[serde(borrow)] may only be used on newtype variants");
}
}
}
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
}
@@ -627,6 +641,7 @@ impl Variant {
other: other.get(),
serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(),
borrow: borrow.get(),
}
}
@@ -699,7 +714,7 @@ pub enum Default {
impl Field {
/// Extract out the `#[serde(...)]` attributes from a struct field.
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self {
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field, attrs: Option<&Variant>) -> Self {
let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
@@ -718,7 +733,13 @@ impl Field {
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 {
match meta_item {
// Parse `#[serde(rename = "foo")]`
+3
View File
@@ -6,7 +6,10 @@
// option. This file may not be copied, modified, or distributed
// 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::str::FromStr;
use self::RenameRule::*;
+1 -1
View File
@@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.17.0")]
extern crate syn;
#[macro_use]
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.13" # remember to update html_root_url
version = "1.0.23" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
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"]
[dependencies]
serde = { version = "1.0", path = "../serde" }
serde = { version = "1.0.16", path = "../serde" }
[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" }
[badges]
+2 -2
View File
@@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use de::Deserializer;
use ser::Serializer;
@@ -215,7 +215,7 @@ where
///
/// assert_de_tokens_error::<S>(
/// &[
/// Token::Struct { name: "S", len: 1 },
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("x"),
/// ],
/// "unknown field `x`, expected `a` or `b`",
+661
View File
@@ -0,0 +1,661 @@
use std::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Readable<T: ?Sized>(T);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Compact<T: ?Sized>(T);
/// Trait to determine whether a value is represented in human-readable or
/// compact form.
///
/// ```
/// extern crate serde;
/// extern crate serde_test;
///
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{Configure, Token, assert_tokens};
///
/// #[derive(Debug, PartialEq)]
/// struct Example(u8, u8);
///
/// impl Serialize for Example {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer,
/// {
/// if serializer.is_human_readable() {
/// format!("{}.{}", self.0, self.1).serialize(serializer)
/// } else {
/// (self.0, self.1).serialize(serializer)
/// }
/// }
/// }
///
/// impl<'de> Deserialize<'de> for Example {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de>,
/// {
/// use serde::de::Error;
/// if deserializer.is_human_readable() {
/// let s = String::deserialize(deserializer)?;
/// let parts: Vec<_> = s.split('.').collect();
/// Ok(Example(
/// parts[0].parse().map_err(D::Error::custom)?,
/// parts[1].parse().map_err(D::Error::custom)?,
/// ))
/// } else {
/// let (x, y) = Deserialize::deserialize(deserializer)?;
/// Ok(Example(x, y))
/// }
/// }
/// }
///
/// fn main() {
/// assert_tokens(
/// &Example(1, 0).compact(),
/// &[
/// Token::Tuple { len: 2 },
/// Token::U8(1),
/// Token::U8(0),
/// Token::TupleEnd,
/// ],
/// );
/// assert_tokens(
/// &Example(1, 0).readable(),
/// &[
/// Token::Str("1.0"),
/// ],
/// );
/// }
/// ```
pub trait Configure {
/// Marks `self` as using `is_human_readable == true`
fn readable(self) -> Readable<Self> where Self: Sized {
Readable(self)
}
/// Marks `self` as using `is_human_readable == false`
fn compact(self) -> Compact<Self> where Self: Sized {
Compact(self)
}
}
impl<T: ?Sized> Configure for T {}
impl<T: ?Sized> Serialize for Readable<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(Readable(serializer))
}
}
impl<T: ?Sized> Serialize for Compact<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(Compact(serializer))
}
}
impl<'de, T> Deserialize<'de> for Readable<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(Readable(deserializer)).map(Readable)
}
}
impl<'de, T> Deserialize<'de> for Compact<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(Compact(deserializer)).map(Compact)
}
}
impl<'de, T> DeserializeSeed<'de> for Readable<T>
where
T: DeserializeSeed<'de>,
{
type Value = T::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
self.0.deserialize(Readable(deserializer))
}
}
impl<'de, T> DeserializeSeed<'de> for Compact<T>
where
T: DeserializeSeed<'de>,
{
type Value = T::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
self.0.deserialize(Compact(deserializer))
}
}
macro_rules! forward_method {
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
(self.0).$name( $($arg),* )
}
};
}
macro_rules! forward_serialize_methods {
( $( $name: ident $arg_type: ty ),* ) => {
$(
forward_method!($name(self, v : $arg_type) -> Result<Self::Ok, Self::Error>);
)*
};
}
macro_rules! impl_serializer {
($wrapper: ident, $is_human_readable : expr) => {
impl<S> Serializer for $wrapper<S>
where
S: Serializer,
{
type Ok = S::Ok;
type Error = S::Error;
type SerializeSeq = $wrapper<S::SerializeSeq>;
type SerializeTuple = $wrapper<S::SerializeTuple>;
type SerializeTupleStruct = $wrapper<S::SerializeTupleStruct>;
type SerializeTupleVariant = $wrapper<S::SerializeTupleVariant>;
type SerializeMap = $wrapper<S::SerializeMap>;
type SerializeStruct = $wrapper<S::SerializeStruct>;
type SerializeStructVariant = $wrapper<S::SerializeStructVariant>;
fn is_human_readable(&self) -> bool {
$is_human_readable
}
forward_serialize_methods!{
serialize_bool bool,
serialize_i8 i8,
serialize_i16 i16,
serialize_i32 i32,
serialize_i64 i64,
serialize_u8 u8,
serialize_u16 u16,
serialize_u32 u32,
serialize_u64 u64,
serialize_f32 f32,
serialize_f64 f64,
serialize_char char,
serialize_str &str,
serialize_bytes &[u8],
serialize_unit_struct &'static str
}
fn serialize_unit(self) -> Result<S::Ok, S::Error> {
self.0.serialize_unit()
}
fn serialize_unit_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<S::Ok, S::Error> {
self.0.serialize_unit_variant(name, variant_index, variant)
}
fn serialize_newtype_struct<T: ?Sized>(
self,
name: &'static str,
value: &T,
) -> Result<S::Ok, S::Error>
where
T: Serialize,
{
self.0.serialize_newtype_struct(name, &$wrapper(value))
}
fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<S::Ok, S::Error>
where
T: Serialize,
{
self.0
.serialize_newtype_variant(name, variant_index, variant, &$wrapper(value))
}
fn serialize_none(self) -> Result<S::Ok, Self::Error> {
self.0.serialize_none()
}
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<S::Ok, Self::Error>
where
T: Serialize,
{
self.0.serialize_some(&$wrapper(value))
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
self.0.serialize_seq(len).map($wrapper)
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
self.0.serialize_tuple(len).map($wrapper)
}
fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
self.0.serialize_tuple_struct(name, len).map($wrapper)
}
fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
self.0
.serialize_tuple_variant(name, variant_index, variant, len)
.map($wrapper)
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
self.0.serialize_map(len).map($wrapper)
}
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
self.0.serialize_struct(name, len).map($wrapper)
}
fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
self.0
.serialize_struct_variant(name, variant_index, variant, len)
.map($wrapper)
}
}
impl<S> SerializeSeq for $wrapper<S>
where
S: SerializeSeq,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_element(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTuple for $wrapper<S>
where
S: SerializeTuple,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_element(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTupleStruct for $wrapper<S>
where
S: SerializeTupleStruct,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTupleVariant for $wrapper<S>
where
S: SerializeTupleVariant,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeMap for $wrapper<S>
where
S: SerializeMap,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_key(&$wrapper(key))
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_value(&$wrapper(value))
}
fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<(), S::Error>
where
K: Serialize,
V: Serialize,
{
self.0.serialize_entry(key, &$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeStruct for $wrapper<S>
where
S: SerializeStruct,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, name: &'static str, field: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(name, &$wrapper(field))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeStructVariant for $wrapper<S>
where
S: SerializeStructVariant,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, name: &'static str, field: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(name, &$wrapper(field))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
}
}
impl_serializer!(Readable, true);
impl_serializer!(Compact, false);
use serde::de::{Visitor, EnumAccess, VariantAccess, MapAccess, DeserializeSeed, SeqAccess, Error};
macro_rules! forward_deserialize_methods {
( $wrapper : ident ( $( $name: ident ),* ) ) => {
$(
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
(self.0).$name($wrapper(visitor))
}
)*
};
}
macro_rules! impl_deserializer {
($wrapper : ident, $is_human_readable : expr) => {
impl <'de, D> Deserializer<'de> for $wrapper<D> where D: Deserializer<'de> {
type Error = D::Error;
forward_deserialize_methods! {
$wrapper (
deserialize_any,
deserialize_bool,
deserialize_u8,
deserialize_u16,
deserialize_u32,
deserialize_u64,
deserialize_i8,
deserialize_i16,
deserialize_i32,
deserialize_i64,
deserialize_f32,
deserialize_f64,
deserialize_char,
deserialize_str,
deserialize_string,
deserialize_bytes,
deserialize_byte_buf,
deserialize_option,
deserialize_unit,
deserialize_seq,
deserialize_map,
deserialize_identifier,
deserialize_ignored_any
)
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_unit_struct(name, $wrapper(visitor))
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_newtype_struct(name, $wrapper(visitor))
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_tuple(len, $wrapper(visitor))
}
fn deserialize_tuple_struct<V>(self, name: &'static str, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_tuple_struct(name, len, $wrapper(visitor))
}
fn deserialize_struct<V>(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_struct(name, fields, $wrapper(visitor))
}
fn deserialize_enum<V>(self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.deserialize_enum(name, variants, $wrapper(visitor))
}
fn is_human_readable(&self) -> bool {
$is_human_readable
}
}
impl<'de, D> Visitor<'de> for $wrapper<D> where D: Visitor<'de> {
type Value = D::Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.0.expecting(formatter)
}
fn visit_bool<E>(self, v: bool) -> Result<D::Value, E> where E: Error {
self.0.visit_bool(v)
}
fn visit_i8<E>(self, v: i8) -> Result<D::Value, E> where E: Error {
self.0.visit_i8(v)
}
fn visit_i16<E>(self, v: i16) -> Result<D::Value, E> where E: Error {
self.0.visit_i16(v)
}
fn visit_i32<E>(self, v: i32) -> Result<D::Value, E> where E: Error {
self.0.visit_i32(v)
}
fn visit_i64<E>(self, v: i64) -> Result<D::Value, E> where E: Error {
self.0.visit_i64(v)
}
fn visit_u8<E>(self, v: u8) -> Result<D::Value, E> where E: Error {
self.0.visit_u8(v)
}
fn visit_u16<E>(self, v: u16) -> Result<D::Value, E> where E: Error {
self.0.visit_u16(v)
}
fn visit_u32<E>(self, v: u32) -> Result<D::Value, E> where E: Error {
self.0.visit_u32(v)
}
fn visit_u64<E>(self, v: u64) -> Result<D::Value, E> where E: Error {
self.0.visit_u64(v)
}
fn visit_f32<E>(self, v: f32) -> Result<D::Value, E> where E: Error {
self.0.visit_f32(v)
}
fn visit_f64<E>(self, v: f64) -> Result<D::Value, E> where E: Error {
self.0.visit_f64(v)
}
fn visit_char<E>(self, v: char) -> Result<D::Value, E> where E: Error {
self.0.visit_char(v)
}
fn visit_str<E>(self, v: &str) -> Result<D::Value, E> where E: Error {
self.0.visit_str(v)
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<D::Value, E> where E: Error {
self.0.visit_borrowed_str(v)
}
fn visit_string<E>(self, v: String) -> Result<D::Value, E> where E: Error {
self.0.visit_string(v)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<D::Value, E> where E: Error {
self.0.visit_bytes(v)
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<D::Value, E> where E: Error {
self.0.visit_borrowed_bytes(v)
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<D::Value, E> where E: Error {
self.0.visit_byte_buf(v)
}
fn visit_none<E>(self) -> Result<D::Value, E> where E: Error {
self.0.visit_none()
}
fn visit_some<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error> where D2: Deserializer<'de> {
self.0.visit_some($wrapper(deserializer))
}
fn visit_unit<E>(self) -> Result<D::Value, E> where E: Error {
self.0.visit_unit()
}
fn visit_newtype_struct<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error> where D2: Deserializer<'de> {
self.0.visit_newtype_struct($wrapper(deserializer))
}
fn visit_seq<V>(self, seq: V) -> Result<D::Value, V::Error> where V: SeqAccess<'de> {
self.0.visit_seq($wrapper(seq))
}
fn visit_map<V>(self, map: V) -> Result<D::Value, V::Error> where V: MapAccess<'de> {
self.0.visit_map($wrapper(map))
}
fn visit_enum<V>(self, data: V) -> Result<D::Value, V::Error> where V: EnumAccess<'de> {
self.0.visit_enum($wrapper(data))
}
}
impl<'de, D> SeqAccess<'de> for $wrapper<D> where D: SeqAccess<'de> {
type Error = D::Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, D::Error> where T: DeserializeSeed<'de> {
self.0.next_element_seed($wrapper(seed))
}
fn size_hint(&self) -> Option<usize> {
self.0.size_hint()
}
}
impl<'de, D> MapAccess<'de> for $wrapper<D> where D: MapAccess<'de> {
type Error = D::Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, D::Error> where K: DeserializeSeed<'de> {
self.0.next_key_seed($wrapper(seed))
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, D::Error> where V: DeserializeSeed<'de> {
self.0.next_value_seed($wrapper(seed))
}
fn size_hint(&self) -> Option<usize> {
self.0.size_hint()
}
}
impl<'de, D> EnumAccess<'de> for $wrapper<D> where D: EnumAccess<'de> {
type Error = D::Error;
type Variant = $wrapper<D::Variant>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de> {
self.0.variant_seed($wrapper(seed)).map(|(value, variant)| (value, $wrapper(variant)))
}
}
impl<'de, D> VariantAccess<'de> for $wrapper<D> where D: VariantAccess<'de> {
type Error = D::Error;
fn unit_variant(self) -> Result<(), D::Error> {
self.0.unit_variant()
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, D::Error> where T: DeserializeSeed<'de> {
self.0.newtype_variant_seed($wrapper(seed))
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.tuple_variant(len, $wrapper(visitor))
}
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
self.0.struct_variant(fields, $wrapper(visitor))
}
}
}
}
impl_deserializer!(Readable, true);
impl_deserializer!(Compact, false);
+42 -36
View File
@@ -100,7 +100,7 @@ impl<'de> Deserializer<'de> {
DeserializerSeqVisitor {
de: self,
len: len,
end: end.clone(),
end: end,
},
)
);
@@ -122,7 +122,7 @@ impl<'de> Deserializer<'de> {
DeserializerMapVisitor {
de: self,
len: len,
end: end.clone(),
end: end,
},
)
);
@@ -165,15 +165,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()),
Token::None => visitor.visit_none(),
Token::Some => visitor.visit_some(self),
Token::Unit => visitor.visit_unit(),
Token::UnitStruct { name: _ } => visitor.visit_unit(),
Token::NewtypeStruct { name: _ } => visitor.visit_newtype_struct(self),
Token::Unit | Token::UnitStruct { .. } => visitor.visit_unit(),
Token::NewtypeStruct { .. } => visitor.visit_newtype_struct(self),
Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, 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::Struct { name: _, len } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { name: _ } => {
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => {
let variant = self.next_token();
let next = self.peek_token();
match (variant, next) {
@@ -195,14 +194,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
}
}
Token::UnitVariant { name: _, variant } => visitor.visit_str(variant),
Token::NewtypeVariant { name: _, variant } => {
Token::UnitVariant { variant, .. } => visitor.visit_str(variant),
Token::NewtypeVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Any),)
}
Token::TupleVariant { name: _, variant, len: _ } => {
Token::TupleVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Seq),)
}
Token::StructVariant { name: _, variant, len: _ } => {
Token::StructVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Map),)
}
Token::SeqEnd | Token::TupleEnd | Token::TupleStructEnd | Token::MapEnd |
@@ -245,10 +244,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
Token::UnitVariant { name: n, variant: _ } |
Token::NewtypeVariant { name: n, variant: _ } |
Token::TupleVariant { name: n, variant: _, len: _ } |
Token::StructVariant { name: n, variant: _, len: _ } if name == n => {
Token::UnitVariant { name: n, .. } |
Token::NewtypeVariant { name: n, .. } |
Token::TupleVariant { name: n, .. } |
Token::StructVariant { name: n, .. } if name == n => {
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
_ => {
@@ -262,7 +261,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
match self.peek_token() {
Token::UnitStruct { name: _ } => {
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
visitor.visit_unit()
}
@@ -275,7 +274,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
match self.peek_token() {
Token::NewtypeStruct { name: _ } => {
Token::NewtypeStruct { .. } => {
assert_next_token!(self, Token::NewtypeStruct { name: name });
visitor.visit_newtype_struct(self)
}
@@ -289,19 +288,19 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{
match self.peek_token() {
Token::Unit |
Token::UnitStruct { name: _ } => {
Token::UnitStruct { .. } => {
self.next_token();
visitor.visit_unit()
}
Token::Seq { len: _ } => {
Token::Seq { .. } => {
self.next_token();
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { len: _ } => {
Token::Tuple { .. } => {
self.next_token();
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { name: _, len: _ } => {
Token::TupleStruct { .. } => {
self.next_token();
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
@@ -323,19 +322,19 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
self.next_token();
visitor.visit_unit()
}
Token::UnitStruct { name: _ } => {
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
visitor.visit_unit()
}
Token::Seq { len: _ } => {
Token::Seq { .. } => {
self.next_token();
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { len: _ } => {
Token::Tuple { .. } => {
self.next_token();
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 });
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
@@ -353,17 +352,24 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
match self.peek_token() {
Token::Struct { name: _, len: n } => {
Token::Struct { len: n, .. } => {
assert_next_token!(self, Token::Struct { name: name, len: n });
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
}
Token::Map { len: _ } => {
Token::Map { .. } => {
self.next_token();
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
}
_ => self.deserialize_any(visitor),
}
}
fn is_human_readable(&self) -> bool {
panic!(
"Types which have different human-readable and compact representations \
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}
//////////////////////////////////////////////////////////////////////////
@@ -442,10 +448,10 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
V: DeserializeSeed<'de>,
{
match self.de.peek_token() {
Token::UnitVariant { name: _, variant: v } |
Token::NewtypeVariant { name: _, variant: v } |
Token::TupleVariant { name: _, variant: v, len: _ } |
Token::StructVariant { name: _, variant: v, len: _ } => {
Token::UnitVariant { variant: v, .. } |
Token::NewtypeVariant { variant: v, .. } |
Token::TupleVariant { variant: v, .. } |
Token::StructVariant { variant: v, .. } => {
let de = v.into_deserializer();
let value = try!(seed.deserialize(de));
Ok((value, self))
@@ -463,7 +469,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token() {
Token::UnitVariant { name: _, variant: _ } => {
Token::UnitVariant { .. } => {
self.de.next_token();
Ok(())
}
@@ -476,7 +482,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
T: DeserializeSeed<'de>,
{
match self.de.peek_token() {
Token::NewtypeVariant { name: _, variant: _ } => {
Token::NewtypeVariant { .. } => {
self.de.next_token();
seed.deserialize(self.de)
}
@@ -489,7 +495,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
V: Visitor<'de>,
{
match self.de.peek_token() {
Token::TupleVariant { name: _, variant: _, len: enum_len } => {
Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token();
if len == enum_len {
@@ -517,7 +523,7 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
V: Visitor<'de>,
{
match self.de.peek_token() {
Token::StructVariant { name: _, variant: _, len: enum_len } => {
Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token();
if fields.len() == enum_len {
+2 -2
View File
@@ -17,13 +17,13 @@ pub struct 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() }
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
fn custom<T: Display>(msg: T) -> Self {
Error { msg: msg.to_string() }
}
}
+17 -3
View File
@@ -155,7 +155,18 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.13")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.23")]
#![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]
extern crate serde;
@@ -164,12 +175,15 @@ mod ser;
mod de;
mod error;
mod configure;
mod token;
mod assert;
pub use token::Token;
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
assert_de_tokens_error};
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
assert_ser_tokens_error, assert_tokens};
pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]
+47 -10
View File
@@ -40,25 +40,43 @@ impl<'a> Serializer<'a> {
macro_rules! assert_next_token {
($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)) => {
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),* }) => {
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() {
Some($pat) if $guard => {}
Some(other) => {
panic!("expected Token::{} but serialized as {}",
stringify!($expected), other);
$expected, other);
}
None => {
panic!("expected Token::{} after end of serialized tokens",
stringify!($expected));
$expected);
}
}
};
@@ -247,10 +265,16 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Seq { len });
Ok(Variant { ser: self, end: Token::SeqEnd })
Ok(Variant {
ser: self,
end: Token::SeqEnd,
})
} else {
assert_next_token!(self, TupleVariant { name, variant, len });
Ok(Variant { ser: self, end: Token::TupleVariantEnd })
Ok(Variant {
ser: self,
end: Token::TupleVariantEnd,
})
}
}
@@ -276,12 +300,25 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Map { len });
Ok(Variant { ser: self, end: Token::MapEnd })
Ok(Variant {
ser: self,
end: Token::MapEnd,
})
} else {
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 {
panic!(
"Types which have different human-readable and compact representations \
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}
pub struct Variant<'s, 'a: 's> {
+1 -1
View File
@@ -15,4 +15,4 @@ serde_derive = { path = "../serde_derive" }
serde_test = { path = "../serde_test" }
[dependencies]
compiletest_rs = { version = "0.2", optional = true }
compiletest_rs = { version = "0.3", optional = true }
+11
View File
@@ -0,0 +1,11 @@
// 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.
#![feature(/*=============================================]
#![=== Serde test suite requires a nightly compiler. ===]
#![====================================================*/)]
+8
View File
@@ -1,3 +1,11 @@
// 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.
#![feature(lang_items, start, compiler_builtins_lib)]
#![no_std]
@@ -0,0 +1,21 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
enum Test<'a> {
#[serde(borrow)] //~^^ HELP: duplicate serde attribute `borrow`
S(#[serde(borrow)] Str<'a>)
}
fn main() {}
@@ -0,0 +1,21 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
enum Test<'a> {
#[serde(borrow)] //~^^ HELP: #[serde(borrow)] may only be used on newtype variants
S { s: Str<'a> }
}
fn main() {}
@@ -16,7 +16,7 @@ mod remote {
}
}
#[derive(Serialize, Deserialize)] //~ ERROR: missing field `b` in initializer of `remote::S`
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::S")]
struct S {
a: u8, //~^^^ ERROR: missing field `b` in initializer of `remote::S`
@@ -19,8 +19,7 @@ mod remote {
#[serde(remote = "remote::S")]
struct S {
//~^^^ ERROR: struct `remote::S` has no field named `b`
//~^^^^ ERROR: struct `remote::S` has no field named `b`
b: u8, //~^^^^^ ERROR: no field `b` on type `&remote::S`
b: u8, //~^^^^ ERROR: no field `b` on type `&remote::S`
}
fn main() {}
+26
View File
@@ -73,3 +73,29 @@ macro_rules! hashmap {
}
}
}
macro_rules! seq_impl {
(seq $first:expr,) => {
seq_impl!(seq $first)
};
($first:expr,) => {
seq_impl!($first)
};
(seq $first:expr) => {
$first.into_iter()
};
($first:expr) => {
Some($first).into_iter()
};
(seq $first:expr , $( $elem: tt)*) => {
$first.into_iter().chain(seq!( $($elem)* ))
};
($first:expr , $($elem: tt)*) => {
Some($first).into_iter().chain(seq!( $($elem)* ))
}
}
macro_rules! seq {
($($tt: tt)*) => {
seq_impl!($($tt)*).collect::<Vec<_>>()
};
}
+4 -4
View File
@@ -135,7 +135,7 @@ fn test_default_struct() {
a5: 123,
},
&[
Token::Struct { name: "DefaultStruct", len: 1 },
Token::Struct { name: "DefaultStruct", len: 3 },
Token::Str("a1"),
Token::I32(1),
@@ -309,7 +309,7 @@ fn test_elt_not_deserialize() {
c: NotDeserializeStruct(123),
e: NotDeserializeEnum::Trouble,
},
&[Token::Struct { name: "ContainsNotDeserialize", len: 3 }, Token::StructEnd],
&[Token::Struct { name: "ContainsNotDeserialize", len: 1 }, Token::StructEnd],
);
}
@@ -331,7 +331,7 @@ fn test_ignore_unknown() {
a5: 123,
},
&[
Token::Struct { name: "DefaultStruct", len: 5 },
Token::Struct { name: "DefaultStruct", len: 3 },
Token::Str("whoops1"),
Token::I32(2),
@@ -359,7 +359,7 @@ fn test_ignore_unknown() {
assert_de_tokens_error::<DenyUnknown>(
&[
Token::Struct { name: "DenyUnknown", len: 2 },
Token::Struct { name: "DenyUnknown", len: 1 },
Token::Str("a1"),
Token::I32(1),
+153 -59
View File
@@ -17,6 +17,7 @@ use std::default::Default;
use std::ffi::{CString, OsString};
use std::rc::Rc;
use std::sync::Arc;
use std::num::Wrapping;
#[cfg(feature = "unstable")]
use std::ffi::CStr;
@@ -28,7 +29,7 @@ extern crate fnv;
use self::fnv::FnvHasher;
extern crate serde_test;
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error};
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token};
#[macro_use]
mod macros;
@@ -48,16 +49,14 @@ struct TupleStruct(i32, i32, i32);
struct Struct {
a: i32,
b: i32,
#[serde(skip_deserializing)]
c: i32,
#[serde(skip_deserializing)] c: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructDenyUnknown {
a: i32,
#[serde(skip_deserializing)]
b: i32,
#[serde(skip_deserializing)] b: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@@ -78,15 +77,13 @@ impl Default for StructDefault<String> {
#[derive(PartialEq, Debug, Deserialize)]
struct StructSkipAll {
#[serde(skip_deserializing)]
a: i32,
#[serde(skip_deserializing)] a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructSkipAllDenyUnknown {
#[serde(skip_deserializing)]
a: i32,
#[serde(skip_deserializing)] a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@@ -109,25 +106,37 @@ enum EnumSkipAll {
//////////////////////////////////////////////////////////////////////////
macro_rules! declare_test {
($name:ident { $($value:expr => $tokens:expr,)+ }) => {
#[test]
fn $name() {
$(
// Test ser/de roundtripping
assert_de_tokens(&$value, $tokens);
// Test that the tokens are ignorable
assert_de_tokens_ignore($tokens);
)+
}
}
}
macro_rules! declare_tests {
(
$readable:tt
$($name:ident { $($value:expr => $tokens:expr,)+ })+
) => {
$(
#[test]
fn $name() {
$(
// Test ser/de roundtripping
assert_de_tokens(&$value.$readable(), $tokens);
// Test that the tokens are ignorable
assert_de_tokens_ignore($tokens);
)+
}
)+
};
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
$(
declare_test!($name { $($value => $tokens,)+ });
#[test]
fn $name() {
$(
// Test ser/de roundtripping
assert_de_tokens(&$value, $tokens);
// Test that the tokens are ignorable
assert_de_tokens_ignore($tokens);
)+
}
)+
}
}
@@ -155,13 +164,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
Token::Map { len: Some(2) },
Token::Str("a"),
Token::I32(1),
Token::Str("ignored"),
]
.into_iter()
.chain(ignorable_tokens.to_vec().into_iter())
.chain(vec![Token::MapEnd].into_iter())
.collect();
].into_iter()
.chain(ignorable_tokens.to_vec().into_iter())
.chain(vec![Token::MapEnd].into_iter())
.collect();
let mut de = serde_test::Deserializer::new(&concated_tokens);
let base = IgnoreBase::deserialize(&mut de).unwrap();
@@ -531,7 +538,7 @@ declare_tests! {
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 },
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
Token::I32(1),
@@ -563,7 +570,7 @@ declare_tests! {
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 },
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
Token::I32(1),
@@ -584,7 +591,7 @@ declare_tests! {
Token::StructEnd,
],
StructSkipAll { a: 0 } => &[
Token::Struct { name: "StructSkipAll", len: 1 },
Token::Struct { name: "StructSkipAll", len: 0 },
Token::Str("a"),
Token::I32(1),
@@ -601,7 +608,7 @@ declare_tests! {
}
test_struct_default {
StructDefault { a: 50, b: "overwritten".to_string() } => &[
Token::Struct { name: "StructDefault", len: 1 },
Token::Struct { name: "StructDefault", len: 2 },
Token::Str("a"),
Token::I32(50),
@@ -610,7 +617,7 @@ declare_tests! {
Token::StructEnd,
],
StructDefault { a: 100, b: "default".to_string() } => &[
Token::Struct { name: "StructDefault", len: 0 },
Token::Struct { name: "StructDefault", len: 2 },
Token::StructEnd,
],
}
@@ -725,17 +732,6 @@ declare_tests! {
Token::SeqEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_ipv6addr {
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
}
test_net_socketaddr {
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::BorrowedStr("/usr/local/lib"),
@@ -761,6 +757,107 @@ declare_tests! {
Token::Bool(true),
],
}
test_wrapping {
Wrapping(1usize) => &[
Token::U32(1),
],
Wrapping(1usize) => &[
Token::U64(1),
],
}
}
declare_tests! {
readable
test_net_ipv4addr_readable {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_ipv6addr_readable {
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
}
test_net_ipaddr_readable {
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_socketaddr_readable {
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
}
}
declare_tests! {
compact
test_net_ipv4addr_compact {
net::Ipv4Addr::from(*b"1234") => &seq![
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd
],
}
test_net_ipv6addr_compact {
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
Token::Tuple { len: 4 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd
],
}
test_net_ipaddr_compact {
net::IpAddr::from(*b"1234") => &seq![
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd
],
}
test_net_socketaddr_compact {
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
Token::Tuple { len: 2 },
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd
],
net::SocketAddr::from((*b"1234", 1234)) => &seq![
Token::NewtypeVariant { name: "SocketAddr", variant: "V4" },
Token::Tuple { len: 2 },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd
],
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
Token::Tuple { len: 2 },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd
],
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
Token::Tuple { len: 2 },
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd
],
}
}
#[cfg(feature = "unstable")]
@@ -836,15 +933,6 @@ fn test_cstr() {
);
}
#[cfg(feature = "unstable")]
#[test]
fn test_net_ipaddr() {
assert_de_tokens(
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
&[Token::Str("1.2.3.4")],
);
}
#[cfg(feature = "unstable")]
#[test]
fn test_cstr_internal_null() {
@@ -866,7 +954,7 @@ fn test_cstr_internal_null_end() {
declare_error_tests! {
test_unknown_field<StructDenyUnknown> {
&[
Token::Struct { name: "StructDenyUnknown", len: 2 },
Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("a"),
Token::I32(0),
@@ -876,14 +964,14 @@ declare_error_tests! {
}
test_skipped_field_is_unknown<StructDenyUnknown> {
&[
Token::Struct { name: "StructDenyUnknown", len: 2 },
Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("b"),
],
"unknown field `b`, expected `a`",
}
test_skip_all_deny_unknown<StructSkipAllDenyUnknown> {
&[
Token::Struct { name: "StructSkipAllDenyUnknown", len: 1 },
Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
Token::Str("a"),
],
"unknown field `a`, there are no fields",
@@ -1086,4 +1174,10 @@ declare_error_tests! {
],
"invalid type: sequence, expected unit struct UnitStruct",
}
test_wrapping_overflow<Wrapping<u16>> {
&[
Token::U32(65_536),
],
"invalid value: integer `65536`, expected u16",
}
}
+61 -9
View File
@@ -10,11 +10,9 @@
// successfully when there are a variety of generics and non-(de)serializable
// types involved.
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
#![deny(warnings)]
// Clippy false positive
// https://github.com/Manishearth/rust-clippy/issues/292
#![cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
#[macro_use]
extern crate serde_derive;
@@ -25,6 +23,7 @@ use self::serde::de::{DeserializeOwned, Deserializer};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::option::Option as StdOption;
use std::result::Result as StdResult;
// Try to trip up the generated code if it fails to use fully qualified paths.
@@ -34,6 +33,12 @@ struct Result;
struct Ok;
#[allow(dead_code)]
struct Err;
#[allow(dead_code)]
struct Option;
#[allow(dead_code)]
struct Some;
#[allow(dead_code)]
struct None;
//////////////////////////////////////////////////////////////////////////
@@ -58,7 +63,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)]
t: Option<&'a T>,
t: StdOption<&'a T>,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
x: X,
}
@@ -79,9 +84,9 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct NoBounds<T> {
t: T,
option: Option<T>,
option: StdOption<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
option_boxed: StdOption<Box<T>>,
}
assert::<NoBounds<i32>>();
@@ -177,8 +182,8 @@ fn test_gen() {
#[derive(Serialize)]
struct OptionStatic<'a> {
a: Option<&'a str>,
b: Option<&'static str>,
a: StdOption<&'a str>,
b: StdOption<&'static str>,
}
assert_ser::<OptionStatic>();
@@ -359,6 +364,12 @@ fn test_gen() {
s: Str<'a>,
}
#[derive(Serialize, Deserialize)]
enum BorrowVariant<'a> {
#[serde(borrow, with = "StrDef")]
S(Str<'a>),
}
mod vis {
pub struct S;
@@ -491,6 +502,47 @@ fn test_gen() {
Unit,
}
assert_ser::<UntaggedVariantWith>();
#[derive(Serialize, Deserialize)]
struct StaticStrStruct<'a> {
a: &'a str,
b: &'static str,
}
#[derive(Serialize, Deserialize)]
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
#[derive(Serialize, Deserialize)]
struct StaticStrNewtypeStruct(&'static str);
#[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> {
Struct {
a: &'a str,
b: &'static str,
},
Tuple(&'a str, &'static str),
Newtype(&'static str),
}
#[derive(Serialize, Deserialize)]
struct SkippedStaticStr {
#[serde(skip_deserializing)]
skipped: &'static str,
other: isize,
}
assert::<SkippedStaticStr>();
macro_rules! T {
() => { () }
}
#[derive(Serialize, Deserialize)]
struct TypeMacro<T> {
mac: T!(),
marker: PhantomData<T>,
}
assert::<TypeMacro<X>>();
}
//////////////////////////////////////////////////////////////////////////
+2 -5
View File
@@ -9,10 +9,8 @@
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_test;
use serde_test::{Token, assert_de_tokens};
use serde_test::{assert_de_tokens, Token};
#[test]
fn test_variant_identifier() {
@@ -51,8 +49,7 @@ fn test_unit_fallthrough() {
enum F {
Aaa,
Bbb,
#[serde(other)]
Other,
#[serde(other)] Other,
}
assert_de_tokens(&F::Other, &[Token::Str("x")]);
+126 -42
View File
@@ -6,6 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(trivial_numeric_casts)]
#[macro_use]
extern crate serde_derive;
@@ -589,11 +591,10 @@ fn test_internally_tagged_enum() {
#[serde(tag = "type")]
enum InternallyTagged {
A { a: u8 },
B { b: u8 },
C,
D(BTreeMap<String, String>),
E(Newtype),
F(Struct),
B,
C(BTreeMap<String, String>),
D(Newtype),
E(Struct),
}
assert_tokens(
@@ -611,35 +612,62 @@ fn test_internally_tagged_enum() {
],
);
assert_tokens(
&InternallyTagged::B { b: 2 },
assert_de_tokens(
&InternallyTagged::A { a: 1 },
&[
Token::Struct { name: "InternallyTagged", len: 2 },
Token::Str("type"),
Token::Str("B"),
Token::Str("b"),
Token::U8(2),
Token::StructEnd,
Token::Seq { len: Some(2) },
Token::Str("A"),
Token::U8(1),
Token::SeqEnd,
],
);
assert_tokens(
&InternallyTagged::C,
&InternallyTagged::B,
&[
Token::Struct { name: "InternallyTagged", len: 1 },
Token::Str("type"),
Token::Str("C"),
Token::Str("B"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::B,
&[
Token::Seq { len: Some(1) },
Token::Str("B"),
Token::SeqEnd,
],
);
assert_tokens(
&InternallyTagged::D(BTreeMap::new()),
&InternallyTagged::C(BTreeMap::new()),
&[
Token::Map { len: Some(1) },
Token::Str("type"),
Token::Str("C"),
Token::MapEnd,
],
);
assert_de_tokens_error::<InternallyTagged>(
&[
Token::Seq { len: Some(2) },
Token::Str("C"),
Token::Map { len: Some(0) },
Token::MapEnd,
Token::SeqEnd,
],
"invalid type: sequence, expected a map",
);
assert_tokens(
&InternallyTagged::D(Newtype(BTreeMap::new())),
&[
Token::Map { len: Some(1) },
@@ -651,24 +679,12 @@ fn test_internally_tagged_enum() {
);
assert_tokens(
&InternallyTagged::E(Newtype(BTreeMap::new())),
&[
Token::Map { len: Some(1) },
Token::Str("type"),
Token::Str("E"),
Token::MapEnd,
],
);
assert_tokens(
&InternallyTagged::F(Struct { f: 6 }),
&InternallyTagged::E(Struct { f: 6 }),
&[
Token::Struct { name: "Struct", len: 2 },
Token::Str("type"),
Token::Str("F"),
Token::Str("E"),
Token::Str("f"),
Token::U8(6),
@@ -677,6 +693,16 @@ fn test_internally_tagged_enum() {
],
);
assert_de_tokens(
&InternallyTagged::E(Struct { f: 6 }),
&[
Token::Seq { len: Some(2) },
Token::Str("E"),
Token::U8(6),
Token::SeqEnd,
],
);
assert_de_tokens_error::<InternallyTagged>(
&[Token::Map { len: Some(0) }, Token::MapEnd],
"missing field `type`",
@@ -691,7 +717,7 @@ fn test_internally_tagged_enum() {
Token::MapEnd,
],
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`, `F`",
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`",
);
}
@@ -760,7 +786,7 @@ fn test_adjacently_tagged_enum() {
}
// unit with no content
assert_tokens(
assert_ser_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 1 },
@@ -772,11 +798,24 @@ fn test_adjacently_tagged_enum() {
],
);
// unit with no content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("t"),
Token::Str("Unit"),
Token::StructEnd,
],
);
// unit with tag first
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 1 },
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("t"),
Token::Str("Unit"),
@@ -792,7 +831,7 @@ fn test_adjacently_tagged_enum() {
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 1 },
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("c"),
Token::Unit,
@@ -808,7 +847,7 @@ fn test_adjacently_tagged_enum() {
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 3 },
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("f"),
Token::Unit,
@@ -949,7 +988,7 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
assert_de_tokens(
&AdjacentlyTagged::Unit,
&[
Token::Struct { name: "AdjacentlyTagged", len: 2},
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("t"),
Token::Str("Unit"),
@@ -963,7 +1002,7 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("t"),
Token::Str("Unit"),
@@ -978,7 +1017,7 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("h"),
],
@@ -987,7 +1026,7 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Struct { name: "AdjacentlyTagged", len: 2 },
Token::Str("c"),
Token::Unit,
@@ -1241,3 +1280,48 @@ fn test_rename_all() {
]
);
}
#[test]
fn test_untagged_newtype_variant_containing_unit_struct_not_map() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Unit;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Message {
Unit(Unit),
Map(BTreeMap<String, String>),
}
assert_tokens(
&Message::Map(BTreeMap::new()),
&[
Token::Map { len: Some(0) },
Token::MapEnd,
],
);
}
#[test]
fn test_internally_tagged_newtype_variant_containing_unit_struct() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Info;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "topic")]
enum Message {
Info(Info),
}
assert_tokens(
&Message::Info(Info),
&[
Token::Map { len: Some(1) },
Token::Str("topic"),
Token::Str("Info"),
Token::MapEnd,
],
);
}
+19 -45
View File
@@ -9,8 +9,6 @@
#[macro_use]
extern crate serde_derive;
extern crate serde;
mod remote {
pub struct Unit;
@@ -87,32 +85,23 @@ mod remote {
#[derive(Serialize, Deserialize)]
struct Test {
#[serde(with = "UnitDef")]
unit: remote::Unit,
#[serde(with = "UnitDef")] unit: remote::Unit,
#[serde(with = "PrimitivePrivDef")]
primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePrivDef")] primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePubDef")]
primitive_pub: remote::PrimitivePub,
#[serde(with = "PrimitivePubDef")] primitive_pub: remote::PrimitivePub,
#[serde(with = "NewtypePrivDef")]
newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePrivDef")] newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePubDef")]
newtype_pub: remote::NewtypePub,
#[serde(with = "NewtypePubDef")] newtype_pub: remote::NewtypePub,
#[serde(with = "TuplePrivDef")]
tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePrivDef")] tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePubDef")]
tuple_pub: remote::TuplePub,
#[serde(with = "TuplePubDef")] tuple_pub: remote::TuplePub,
#[serde(with = "StructPrivDef")]
struct_priv: remote::StructPriv,
#[serde(with = "StructPrivDef")] struct_priv: remote::StructPriv,
#[serde(with = "StructPubDef")]
struct_pub: remote::StructPub,
#[serde(with = "StructPubDef")] struct_pub: remote::StructPub,
}
#[derive(Serialize, Deserialize)]
@@ -121,10 +110,7 @@ struct UnitDef;
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePriv")]
struct PrimitivePrivDef(
#[serde(getter = "remote::PrimitivePriv::get")]
u8
);
struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePub")]
@@ -133,53 +119,41 @@ struct PrimitivePubDef(u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePriv")]
struct NewtypePrivDef(
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")]
remote::Unit
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePub")]
struct NewtypePubDef(
#[serde(with = "UnitDef")]
remote::Unit
);
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePriv")]
struct TuplePrivDef(
#[serde(getter = "remote::TuplePriv::first")]
u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")]
remote::Unit
#[serde(getter = "remote::TuplePriv::first")] u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePub")]
struct TuplePubDef(
u8,
#[serde(with = "UnitDef")]
remote::Unit
);
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPriv")]
struct StructPrivDef {
#[serde(getter = "remote::StructPriv::a")]
a: u8,
#[serde(getter = "remote::StructPriv::a")] a: u8,
#[serde(getter = "remote::StructPriv::b")]
#[serde(with= "UnitDef")]
#[serde(with = "UnitDef")]
b: remote::Unit,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")]
struct StructPubDef {
#[allow(dead_code)]
a: u8,
#[allow(dead_code)] a: u8,
#[allow(dead_code)]
#[serde(with= "UnitDef")]
#[serde(with = "UnitDef")]
b: remote::Unit,
}
+49
View File
@@ -0,0 +1,49 @@
// 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.
extern crate serde_test;
use self::serde_test::{assert_tokens, Configure, Token};
use std::net;
#[macro_use]
#[allow(unused_macros)]
mod macros;
#[test]
fn ip_addr_roundtrip() {
assert_tokens(
&net::IpAddr::from(*b"1234").compact(),
&seq![
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
],
);
}
#[test]
fn socked_addr_roundtrip() {
assert_tokens(
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
&seq![
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
Token::Tuple { len: 2 },
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd,
],
);
}
+107 -36
View File
@@ -16,14 +16,13 @@ use std::time::{Duration, UNIX_EPOCH};
use std::ffi::CString;
use std::rc::Rc;
use std::sync::Arc;
use std::num::Wrapping;
#[cfg(unix)]
use std::str;
extern crate serde;
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};
extern crate fnv;
use self::fnv::FnvHasher;
@@ -52,19 +51,29 @@ enum Enum {
One(i32),
Seq(i32, i32),
Map { a: i32, b: i32 },
#[serde(skip_serializing)]
SkippedUnit,
#[serde(skip_serializing)]
SkippedOne(i32),
#[serde(skip_serializing)]
SkippedSeq(i32, i32),
#[serde(skip_serializing)]
SkippedMap { _a: i32, _b: i32 },
#[serde(skip_serializing)] SkippedUnit,
#[serde(skip_serializing)] SkippedOne(i32),
#[serde(skip_serializing)] SkippedSeq(i32, i32),
#[serde(skip_serializing)] SkippedMap { _a: i32, _b: i32 },
}
//////////////////////////////////////////////////////////////////////////
macro_rules! declare_tests {
(
$readable:tt
$($name:ident { $($value:expr => $tokens:expr,)+ })+
) => {
$(
#[test]
fn $name() {
$(
assert_ser_tokens(&$value.$readable(), $tokens);
)+
}
)+
};
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
$(
#[test]
@@ -354,17 +363,6 @@ declare_tests! {
Token::StructEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_ipv6addr {
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
}
test_net_socketaddr {
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),
@@ -395,6 +393,92 @@ declare_tests! {
Token::Bool(true),
],
}
test_wrapping {
Wrapping(1usize) => &[
Token::U64(1),
],
}
}
declare_tests! {
readable
test_net_ipv4addr_readable {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_ipv6addr_readable {
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
}
test_net_ipaddr_readable {
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
}
test_net_socketaddr_readable {
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
}
}
declare_tests! {
compact
test_net_ipv4addr_compact {
net::Ipv4Addr::from(*b"1234") => &seq![
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
],
}
test_net_ipv6addr_compact {
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
],
}
test_net_ipaddr_compact {
net::IpAddr::from(*b"1234") => &seq![
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
],
}
test_net_socketaddr_compact {
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
Token::Tuple { len: 2 },
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd,
],
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
Token::Tuple { len: 2 },
Token::Tuple { len: 4 },
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd,
],
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
Token::Tuple { len: 2 },
Token::Tuple { len: 16 },
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
Token::U16(1234),
Token::TupleEnd,
],
}
}
// Serde's implementation is not unstable, but the constructors are.
@@ -422,15 +506,6 @@ declare_tests! {
}
}
#[cfg(feature = "unstable")]
#[test]
fn test_net_ipaddr() {
assert_ser_tokens(
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
&[Token::Str("1.2.3.4")],
);
}
#[test]
#[cfg(unix)]
fn test_cannot_serialize_paths() {
@@ -444,11 +519,7 @@ fn test_cannot_serialize_paths() {
let mut path_buf = PathBuf::new();
path_buf.push(path);
assert_ser_tokens_error(
&path_buf,
&[],
"path contains invalid UTF-8 characters",
);
assert_ser_tokens_error(&path_buf, &[], "path contains invalid UTF-8 characters");
}
#[test]
+3
View File
@@ -34,6 +34,9 @@ if [ -n "${CLIPPY}" ]; then
cd "$DIR/serde_derive"
cargo clippy -- -Dclippy
cd "$DIR/serde_test"
cargo clippy -- -Dclippy
cd "$DIR/test_suite"
cargo clippy --features unstable -- -Dclippy