Compare commits

...

90 Commits

Author SHA1 Message Date
David Tolnay 807bd20a64 Release 1.0.167 2023-07-06 16:25:48 -07:00
David Tolnay ed9a140348 Merge pull request #2444 from Mingun/dedup
Simplify code for generation of struct deserializers
2023-07-06 16:25:15 -07:00
David Tolnay 2de7c2bea2 Resolve redundant_static_lifetimes clippy lint from PR 2471
error: constants have by default a `'static` lifetime
        --> serde/src/de/impls.rs:2467:24
         |
    2467 |     pub const FIELDS: &'static [&'static str] = &["end"];
         |                       -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
         = note: `-D clippy::redundant-static-lifetimes` implied by `-D clippy::all`

    error: constants have by default a `'static` lifetime
        --> serde/src/de/impls.rs:2467:34
         |
    2467 |     pub const FIELDS: &'static [&'static str] = &["end"];
         |                                 -^^^^^^^---- help: consider removing `'static`: `&str`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes

    error: constants have by default a `'static` lifetime
        --> serde/src/de/impls.rs:2605:24
         |
    2605 |     pub const FIELDS: &'static [&'static str] = &["start"];
         |                       -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes

    error: constants have by default a `'static` lifetime
        --> serde/src/de/impls.rs:2605:34
         |
    2605 |     pub const FIELDS: &'static [&'static str] = &["start"];
         |                                 -^^^^^^^---- help: consider removing `'static`: `&str`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
2023-07-06 16:18:39 -07:00
David Tolnay e6a4a3772e Delete unuseful RangeFull impls 2023-07-06 16:10:21 -07:00
David Tolnay 0fca04e1a6 Merge pull request 2471 from tbu-/pr_more_ranges 2023-07-06 16:09:13 -07:00
David Tolnay 92bfc8d3af Merge pull request #2290 from Mingun/enum-tests-and-cleanup
Remove unused `impl` and unnecessary struct-wrapper around tuple
2023-07-06 16:02:27 -07:00
David Tolnay fa0312ac45 More formatting of doc tests and example code 2023-07-06 15:56:47 -07:00
David Tolnay 1920b694aa Declare required automod dev-dependency
1.0.0 does not work with workspaces.

    error: No such file or directory (os error 2)
     --> test_suite/tests/regression.rs:2:5
      |
    2 |     automod::dir!("tests/regression");
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |
      = note: this error originates in the macro `automod::dir` (in Nightly builds, run with -Z macro-backtrace for more info)
2023-07-06 15:50:32 -07:00
David Tolnay 3bfd41d624 Format doctests using rustfmt's format_code_in_doc_comments
cargo fmt -- --config format_code_in_doc_comments=true
2023-07-06 15:44:32 -07:00
David Tolnay 290449f19b Fix doc tests to work whether or not serde derive feature is used 2023-07-06 15:40:12 -07:00
David Tolnay 3a1f387e69 Merge pull request #2493 from dtolnay/docedition
Update documentation example code to 2021 edition
2023-07-06 15:40:03 -07:00
David Tolnay 541603ac94 Fix doc tests for 2021 edition 2023-07-06 15:36:17 -07:00
David Tolnay 0666fbfa20 Update documentation example code to 2021 edition 2023-07-06 15:17:05 -07:00
David Tolnay ea071ae1d4 Add CI job using minimal-versions 2023-07-05 10:01:33 -07:00
David Tolnay 992a01bad2 Sort dependency features in Cargo.toml 2023-07-04 12:12:31 -07:00
David Tolnay d640b5624f Add no-alloc category to the macro crate also 2023-07-03 14:05:32 -07:00
David Tolnay 48479e4bae Release 1.0.166 2023-07-03 11:33:19 -07:00
David Tolnay dfaf48bc09 Add no-std::no-alloc category 2023-07-03 11:32:55 -07:00
David Tolnay dcbc3e0162 Release 1.0.165 2023-07-03 04:21:59 -07:00
David Tolnay 0289d31724 Fix -Zminimal-versions build 2023-07-03 04:21:14 -07:00
David Tolnay 015e39776f No need for single-element vec for chaining one element 2023-07-02 21:11:09 -07:00
David Tolnay 6a9a21f178 Resolve useless_conversion clippy lint in test
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
       --> test_suite/tests/test_de.rs:202:12
        |
    202 |     .chain(vec![Token::MapEnd].into_iter())
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![Token::MapEnd]`
        |
    note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
       --> /home/david/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:522:12
        |
    522 |         U: IntoIterator<Item = Self::Item>,
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
        = note: `-D clippy::useless-conversion` implied by `-D clippy::all`
2023-07-02 21:10:06 -07:00
David Tolnay 81ac54b20d Resolve redundant_closure_call clippy lint
error: try not to call a closure in the expression where it is declared
        --> serde/src/de/impls.rs:1590:76
         |
    1590 |                       <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
         |                                                                              ^^^^^^^^^^^^^^
    ...
    1620 | / parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
    1621 | |     ip, port, 0, 0
    1622 | | ));
         | |__- in this macro invocation
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
         = note: `-D clippy::redundant-closure-call` implied by `-D clippy::all`
         = note: this error originates in the macro `parse_socket_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
2023-07-02 21:08:50 -07:00
David Tolnay 6b4e75520a Resolve explicit_iter_loop pedantic clippy lint
error: it is more concise to loop over references to containers instead of using explicit iteration methods
        --> serde/src/private/de.rs:2761:22
         |
    2761 |         for entry in self.0.iter_mut() {
         |                      ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *self.0`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
         = note: `-D clippy::explicit-iter-loop` implied by `-D clippy::pedantic`

    error: it is more concise to loop over references to containers instead of using explicit iteration methods
       --> serde_derive/src/internals/check.rs:202:20
        |
    202 |     for variant in variants.iter() {
        |                    ^^^^^^^^^^^^^^^ help: to write this more concisely, try: `variants`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
        = note: `-D clippy::explicit-iter-loop` implied by `-D clippy::pedantic`

    error: it is more concise to loop over references to containers instead of using explicit iteration methods
       --> serde_derive/src/bound.rs:262:28
        |
    262 |             for variant in variants.iter() {
        |                            ^^^^^^^^^^^^^^^ help: to write this more concisely, try: `variants`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
2023-07-02 21:08:44 -07:00
David Tolnay b053b4f492 Touch up early return in Enum checks 2023-07-02 21:08:44 -07:00
Mingun 4cf1fec575 Replace several linked variables with enumeration for tuples 2023-06-26 20:55:52 +05:00
Mingun ee7d77defa Replace several linked variables with enumeration for structs 2023-06-26 20:55:52 +05:00
Mingun d0dfc4577e Replace enum with boolean parameter 2023-06-26 20:55:52 +05:00
Mingun bbbd1d24c9 Move deserialize_generated_identifier out from if because the call is same in both arms 2023-06-26 20:55:51 +05:00
Mingun fb3a9e0d7c Simplify check for missing fields 2023-06-26 20:55:51 +05:00
Mingun 5ffebeb6ef Actually, field_names_idents can be calculated using the same code in both cases
When !cattrs.has_flatten() all fields is !field.attrs.flatten()

Co-authored-by: Oliver Schneider <oli-obk@users.noreply.github.com>
2023-06-26 20:55:51 +05:00
Mingun 75db73066b Inline deserialize_struct_as_map_visitor and deserialize_struct_as_struct_visitor 2023-06-26 20:55:51 +05:00
Mingun 2796833c82 Pull up call to deserialize_map because it's identical 2023-06-26 20:55:50 +05:00
Mingun 95730dc7f7 Reorder variables to match order in final quote! 2023-06-26 20:55:50 +05:00
Mingun 795261919f Generate visit_seq only when needed 2023-06-26 20:55:50 +05:00
Mingun 3783a30ae7 Remove TaggedContent, replace it by a tuple
That type does not give any benefits so we can avoid that hidden public but no-API struct
2023-06-24 20:49:49 +05:00
Mingun b61ec84886 Remove implementation of DeserializeSeed for TaggedContentVisitor
It is not used anywhere
2023-06-24 20:48:09 +05:00
Mingun 780a461d92 Generate one deserializer rather than in each arm 2023-06-24 20:48:08 +05:00
David Tolnay c0ba323166 Support a manual trigger on CI workflow 2023-06-23 22:50:52 -07:00
David Tolnay 20a48c9580 Remove .clippy.toml in favor of respecting rust-version from Cargo.toml 2023-06-15 18:31:38 -07:00
David Tolnay 09938803af Resolve redundant_static_lifetimes clippy lint 2023-06-15 18:31:38 -07:00
David Tolnay 6d0b43a220 Resolve redundant_field_names clippy lint 2023-06-15 18:31:38 -07:00
Tobias Bucher e76e87a430 Add Serialize/Deserialize impls for Range{From,Full,To}
CC #796
CC #1466
CC #1713
2023-06-09 15:11:44 +02:00
David Tolnay 8a4dfa7231 Merge pull request #2466 from Mingun/fix-de-count-of-field
Fix incorrect count of fields passed to tuple deserialization methods
2023-06-07 22:13:08 -07:00
David Tolnay 107018c628 Release 1.0.164 2023-06-07 22:05:07 -07:00
David Tolnay a398237930 Point out serde(untagged) variants which are out of order
Previously if someone wrote an enum containing:

- `A` (untagged)
- `B` (tagged)
- `C` (tagged)
- `D` (untagged)
- `E` (tagged)
- `F` (untagged)

serde_derive would produce errors referring to B and E only, saying
you're supposed to put untagged variants at the end. The choice of B and
E for this error doesn't make a lot of sense because in order to resolve
the issue, the user must either:

- move A and D down

or:

- move B, C, and E up.

This commit changes the error to appear on A and D instead.
2023-06-07 21:49:30 -07:00
David Tolnay b63c65d7f5 Merge pull request #2470 from dtolnay/contentref
Reuse a single ContentRefDeserializer throughout untagged enum deserialization
2023-06-07 21:38:49 -07:00
David Tolnay f60324e883 Reuse a single ContentRefDeserializer throughout untagged enum deserialization 2023-06-07 21:33:14 -07:00
David Tolnay 361c23a09a Simplify enumerate().find(...) -> Iterator::position 2023-06-07 21:23:31 -07:00
David Tolnay 43b23c7ea0 Format PR 2403 with rustfmt 2023-06-07 21:18:30 -07:00
David Tolnay 6081497506 Resolve semicolon_if_nothing_returned pedantic clippy lint
error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/ast.rs:161:13
        |
    161 |             seen_untagged = variant.attrs.untagged()
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `seen_untagged = variant.attrs.untagged();`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
        = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D clippy::pedantic`

    error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/ast.rs:159:17
        |
    159 | ...   cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum")
        |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
2023-06-07 21:17:24 -07:00
David Ewert 48e5753e76 Allowed Enum variants to be individually marked as untagged (#2403) 2023-06-07 20:58:59 -07:00
David Tolnay bbba632ab3 Revert "Ui tests with compile_error resolved at call site"
This reverts commit e77db40b8d.
2023-06-07 20:50:51 -07:00
David Tolnay e77db40b8d Ui tests with compile_error resolved at call site 2023-06-07 20:02:04 -07:00
Mingun 2c1f62d4b4 Fix incorrect count of fields passed to tuple deserialization methods
This count should mean the number of fields expected in the serialized form,
so if some fields are skipped, they shouldn't be counted

Methods affected:
- Deserializer::deserialize_tuple
- Deserializer::deserialize_tuple_struct
- VariantAccess::tuple_variant
2023-05-28 23:17:05 +05:00
David Tolnay 1aebdc2760 Release serde_derive_internals 0.28.0 2023-05-25 08:20:10 -07:00
David Tolnay 705e58be8c Merge pull request #2464 from serde-rs/combine
Use syn::Error's combine() API instead of Vec<syn::Error>
2023-05-25 08:19:16 -07:00
David Tolnay 7c2c12aa43 Use syn::Error's combine() API instead of Vec<syn::Error> 2023-05-25 08:10:14 -07:00
David Tolnay a0f850f15b Show error details during miri setup in CI
Without this, if it fails, the only information printed is useless:

    Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)...
    fatal error: failed to build sysroot; run `cargo miri setup` to see the error details
2023-05-23 08:29:47 -07:00
David Tolnay fccb9499bc Release 1.0.163 2023-05-10 00:47:53 -07:00
David Tolnay a139ab2572 Adjust PR 2446 with less overgeneralized name 2023-05-10 00:45:52 -07:00
David Tolnay 1d910a484c Format with rustfmt 1.5.2-nightly 2023-05-10 00:40:39 -07:00
David Tolnay ee9166ec97 Revise comments on the FlatMapDeserializer entry taker 2023-05-10 00:39:10 -07:00
David Tolnay b5a9eff32e Resolve while_let_on_iterator clippy lint
warning: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2905:9
         |
    2905 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in self.iter.by_ref()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
         = note: `#[warn(clippy::while_let_on_iterator)]` on by default
2023-05-10 00:23:38 -07:00
David Tolnay 9441a29663 Merge pull request #2446 from Mingun/dedup2
Eliminate some duplicated code
2023-05-10 00:13:44 -07:00
Mingun ab6588ef74 Extract duplicated code into a function 2023-05-08 10:39:30 +05:00
Mingun 1d11f03449 Extract logic of taking flattened fields into a function 2023-05-08 10:39:27 +05:00
Mingun e11d01fe1d Remove constructors for FlatMapAccess and FlatStructAccess
They are used only in one place each, so for simplifying understanding it is better to inline them
2023-05-08 09:40:06 +05:00
Mingun a901f50850 FlatMapAccess and FlatStructAccess does not need to be public 2023-05-08 09:37:15 +05:00
Mingun c399e9c368 Remove FlatInternallyTaggedAccess because it is the same as FlatMapAccess 2023-05-08 09:25:18 +05:00
David Tolnay 25381be0c9 Merge pull request #2442 from taiki-e/derive-build-script
Remove build script from serde_derive
2023-05-05 14:35:09 -07:00
Taiki Endo ef2a7c753f Remove build script from serde_derive
The current serde_derive's MSRV is 1.56, and both underscore consts and
ptr::addr_of! are always available.
2023-05-06 05:34:38 +09:00
David Tolnay 99f165b45a Release 1.0.162 2023-05-04 18:46:55 -07:00
David Tolnay 2fb5560746 Attempt to generate just one copy of TagContentOtherFieldVisitor's field matching 2023-05-04 18:42:21 -07:00
David Tolnay bd653ab30c Format PR 2377 with rustfmt 2023-05-04 18:42:21 -07:00
David Tolnay b5d68aedaa Merge pull request #2377 from mfro/master
Allow bytes for adjacently tagged enums
2023-05-04 18:39:57 -07:00
David Tolnay 624879c4c6 Merge pull request #2441 from dtolnay/test
Reimplement tests that touched serde_test internal API
2023-05-04 17:42:07 -07:00
David Tolnay bd9e9abf35 Reimplement tests that touched serde_test internal API 2023-05-04 17:38:58 -07:00
David Tolnay 3e4a23cbd0 Release 1.0.161 2023-05-04 16:45:18 -07:00
David Tolnay 6326ceec3f Don't panic in serde_test on running out of tokens 2023-05-04 16:38:20 -07:00
David Tolnay 8f4d37c7ec Convert serde_test's assert_next_token from macro to function 2023-05-04 16:34:14 -07:00
David Tolnay 1b8290b318 Convert serde_test's unexpected from macro to function 2023-05-04 16:30:34 -07:00
David Tolnay 48193fbccd Merge pull request #2435 from Mingun/hitchhiker-guide
Don't panic in serde_test
2023-05-04 16:27:35 -07:00
Mingun ac8ea72d88 Don't panic in serde_test
Panics lead to reporting errors in tests inside of serde_test internals,
returning errors moves the report location to the corresponding assert_tokens
expression
2023-04-30 00:06:51 +05:00
David Tolnay f583401284 Merge pull request #2433 from Mingun/rm-gitattributes
Remove unused after .gitattributes
2023-04-26 12:04:04 -07:00
Mingun 2d88228b7d Remove unused after a649190a4d .gitattributes 2023-04-26 23:54:09 +05:00
David Tolnay 0c6a2bbf79 Release 1.0.160 2023-04-10 22:15:49 -07:00
David Tolnay a80d830f27 Merge pull request #2426 from compiler-errors/dont-doc-private
Make derived serializer/deserializer internals `doc(hidden)`
2023-04-10 22:12:35 -07:00
Michael Goulet 5f3fd9994e Make serializer/deserializer internals doc(hidden) 2023-04-10 21:41:50 -07:00
Max Froehlich a803ec1c1f Allow bytes for adjantly tagged enums 2023-02-18 12:49:23 -08:00
54 changed files with 1495 additions and 1024 deletions
-1
View File
@@ -1 +0,0 @@
test_suite/tests/expand/*.expanded.rs linguist-generated
+12
View File
@@ -3,6 +3,7 @@ name: CI
on: on:
push: push:
pull_request: pull_request:
workflow_dispatch:
schedule: [cron: "40 1 * * *"] schedule: [cron: "40 1 * * *"]
permissions: permissions:
@@ -127,6 +128,16 @@ jobs:
- uses: dtolnay/rust-toolchain@1.36.0 - uses: dtolnay/rust-toolchain@1.36.0
- run: cd serde && cargo build --no-default-features --features alloc - run: cd serde && cargo build --no-default-features --features alloc
minimal:
name: Minimal versions
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly
- run: cargo generate-lockfile -Z minimal-versions
- run: cargo check --locked --workspace
clippy: clippy:
name: Clippy name: Clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -149,6 +160,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@miri - uses: dtolnay/rust-toolchain@miri
- run: cargo miri setup
- run: cd serde && cargo miri test --features derive,rc,unstable - run: cd serde && cargo miri test --features derive,rc,unstable
env: env:
MIRIFLAGS: -Zmiri-strict-provenance MIRIFLAGS: -Zmiri-strict-provenance
+1 -1
View File
@@ -48,7 +48,7 @@ serde_json = "1.0"
<p></p> <p></p>
```rust ```rust
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct Point { struct Point {
+1 -1
View File
@@ -16,7 +16,7 @@ You may be looking for:
## Serde in action ## Serde in action
```rust ```rust
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct Point { struct Point {
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+3 -3
View File
@@ -1,9 +1,9 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.159" # remember to update html_root_url and serde_derive dependency version = "1.0.167" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["encoding", "no-std"] categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
documentation = "https://docs.rs/serde" documentation = "https://docs.rs/serde"
homepage = "https://serde.rs" homepage = "https://serde.rs"
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19" rust-version = "1.19"
[dependencies] [dependencies]
serde_derive = { version = "=1.0.159", optional = true, path = "../serde_derive" } serde_derive = { version = "=1.0.167", optional = true, path = "../serde_derive" }
[dev-dependencies] [dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
+3 -4
View File
@@ -10,13 +10,12 @@ use de::{
/// any type, except that it does not store any information about the data that /// any type, except that it does not store any information about the data that
/// gets deserialized. /// gets deserialized.
/// ///
/// ```edition2018 /// ```edition2021
/// use std::fmt;
/// use std::marker::PhantomData;
///
/// use serde::de::{ /// use serde::de::{
/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor, /// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor,
/// }; /// };
/// use std::fmt;
/// use std::marker::PhantomData;
/// ///
/// /// A seed that can be used to deserialize only the `n`th element of a sequence /// /// A seed that can be used to deserialize only the `n`th element of a sequence
/// /// while efficiently discarding elements of any type before or after index `n`. /// /// while efficiently discarding elements of any type before or after index `n`.
+294 -21
View File
@@ -994,7 +994,8 @@ seq_impl!(
HashSet::clear, HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve, HashSet::reserve,
HashSet::insert); HashSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
@@ -1409,16 +1410,14 @@ macro_rules! map_impl {
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
map_impl!( map_impl!(BTreeMap<K: Ord, V>, map, BTreeMap::new());
BTreeMap<K: Ord, V>,
map,
BTreeMap::new());
#[cfg(feature = "std")] #[cfg(feature = "std")]
map_impl!( map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>, HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map, map,
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())); HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())
);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1451,7 +1450,7 @@ macro_rules! variant_identifier {
$($variant),* $($variant),*
} }
static $variants_name: &'static [&'static str] = &[$(stringify!($variant)),*]; static $variants_name: &[&str] = &[$(stringify!($variant)),*];
impl<'de> Deserialize<'de> for $name_kind { impl<'de> Deserialize<'de> for $name_kind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -1588,7 +1587,7 @@ macro_rules! parse_socket_impl {
if deserializer.is_human_readable() { if deserializer.is_human_readable() {
deserializer.deserialize_str(FromStrVisitor::new($expecting)) deserializer.deserialize_str(FromStrVisitor::new($expecting))
} else { } else {
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port)) <(_, u16)>::deserialize(deserializer).map($new)
} }
} }
} }
@@ -1615,12 +1614,10 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, net::SocketAddrV4::new); parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, |(ip, port)| net::SocketAddrV4::new(ip, port));
#[cfg(feature = "std")] #[cfg(feature = "std")]
parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new( parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0));
ip, port, 0, 0
));
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -2099,7 +2096,7 @@ impl<'de> Deserialize<'de> for Duration {
} }
} }
const FIELDS: &'static [&'static str] = &["secs", "nanos"]; const FIELDS: &[&str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor) deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
} }
} }
@@ -2241,7 +2238,7 @@ impl<'de> Deserialize<'de> for SystemTime {
} }
} }
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"]; const FIELDS: &[&str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor)); let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
#[cfg(not(no_systemtime_checked_add))] #[cfg(not(no_systemtime_checked_add))]
let ret = UNIX_EPOCH let ret = UNIX_EPOCH
@@ -2259,9 +2256,9 @@ impl<'de> Deserialize<'de> for SystemTime {
// //
// #[derive(Deserialize)] // #[derive(Deserialize)]
// #[serde(deny_unknown_fields)] // #[serde(deny_unknown_fields)]
// struct Range { // struct Range<Idx> {
// start: u64, // start: Idx,
// end: u32, // end: Idx,
// } // }
impl<'de, Idx> Deserialize<'de> for Range<Idx> impl<'de, Idx> Deserialize<'de> for Range<Idx>
where where
@@ -2309,7 +2306,7 @@ mod range {
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &'static [&'static str] = &["start", "end"]; pub const FIELDS: &[&str] = &["start", "end"];
// If this were outside of the serde crate, it would just use: // If this were outside of the serde crate, it would just use:
// //
@@ -2435,6 +2432,282 @@ mod range {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct RangeFrom<Idx> {
// start: Idx,
// }
impl<'de, Idx> Deserialize<'de> for RangeFrom<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let start = try!(deserializer.deserialize_struct(
"RangeFrom",
range_from::FIELDS,
range_from::RangeFromVisitor {
expecting: "struct RangeFrom",
phantom: PhantomData,
},
));
Ok(start..)
}
}
mod range_from {
use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &[&str] = &["end"];
// If this were outside of the serde crate, it would just use:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
enum Field {
End,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`end`")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"end" => Ok(Field::End),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
b"end" => Ok(Field::End),
_ => {
let value = ::__private::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
pub struct RangeFromVisitor<Idx> {
pub expecting: &'static str,
pub phantom: PhantomData<Idx>,
}
impl<'de, Idx> Visitor<'de> for RangeFromVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = Idx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expecting)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let end: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
Ok(end)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut end: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::End => {
if end.is_some() {
return Err(<A::Error as Error>::duplicate_field("end"));
}
end = Some(try!(map.next_value()));
}
}
}
let end = match end {
Some(end) => end,
None => return Err(<A::Error as Error>::missing_field("end")),
};
Ok(end)
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct RangeTo<Idx> {
// start: Idx,
// }
impl<'de, Idx> Deserialize<'de> for RangeTo<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let end = try!(deserializer.deserialize_struct(
"RangeTo",
range_to::FIELDS,
range_to::RangeToVisitor {
expecting: "struct RangeTo",
phantom: PhantomData,
},
));
Ok(..end)
}
}
mod range_to {
use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &[&str] = &["start"];
// If this were outside of the serde crate, it would just use:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Start,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`start`")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"start" => Ok(Field::Start),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
b"start" => Ok(Field::Start),
_ => {
let value = ::__private::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
pub struct RangeToVisitor<Idx> {
pub expecting: &'static str,
pub phantom: PhantomData<Idx>,
}
impl<'de, Idx> Visitor<'de> for RangeToVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = Idx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expecting)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let start: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
Ok(start)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut start: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::Start => {
if start.is_some() {
return Err(<A::Error as Error>::duplicate_field("start"));
}
start = Some(try!(map.next_value()));
}
}
}
let start = match start {
Some(start) => start,
None => return Err(<A::Error as Error>::missing_field("start")),
};
Ok(start)
}
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))] #[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))]
impl<'de, T> Deserialize<'de> for Bound<T> impl<'de, T> Deserialize<'de> for Bound<T>
where where
@@ -2535,7 +2808,7 @@ where
} }
} }
const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"]; const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"];
deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData)) deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData))
} }
@@ -2643,7 +2916,7 @@ where
} }
} }
const VARIANTS: &'static [&'static str] = &["Ok", "Err"]; const VARIANTS: &[&str] = &["Ok", "Err"];
deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData)) deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData))
} }
@@ -2709,7 +2982,7 @@ struct FromStrVisitor<T> {
impl<T> FromStrVisitor<T> { impl<T> FromStrVisitor<T> {
fn new(expecting: &'static str) -> Self { fn new(expecting: &'static str) -> Self {
FromStrVisitor { FromStrVisitor {
expecting: expecting, expecting,
ty: PhantomData, ty: PhantomData,
} }
} }
+27 -31
View File
@@ -162,7 +162,7 @@ macro_rules! declare_error_trait {
/// ///
/// The message should not be capitalized and should not end with a period. /// The message should not be capitalized and should not end with a period.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::str::FromStr; /// # use std::str::FromStr;
/// # /// #
/// # struct IpAddr; /// # struct IpAddr;
@@ -307,7 +307,7 @@ declare_error_trait!(Error: Sized + Debug + Display);
/// This is used as an argument to the `invalid_type`, `invalid_value`, and /// This is used as an argument to the `invalid_type`, `invalid_value`, and
/// `invalid_length` methods of the `Error` trait to build error messages. /// `invalid_length` methods of the `Error` trait to build error messages.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::fmt; /// # use std::fmt;
/// # /// #
/// # use serde::de::{self, Unexpected, Visitor}; /// # use serde::de::{self, Unexpected, Visitor};
@@ -432,10 +432,9 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// Within the context of a `Visitor` implementation, the `Visitor` itself /// Within the context of a `Visitor` implementation, the `Visitor` itself
/// (`&self`) is an implementation of this trait. /// (`&self`) is an implementation of this trait.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::fmt;
/// #
/// # use serde::de::{self, Unexpected, Visitor}; /// # use serde::de::{self, Unexpected, Visitor};
/// # use std::fmt;
/// # /// #
/// # struct Example; /// # struct Example;
/// # /// #
@@ -457,7 +456,7 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// ///
/// Outside of a `Visitor`, `&"..."` can be used. /// Outside of a `Visitor`, `&"..."` can be used.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{self, Unexpected}; /// # use serde::de::{self, Unexpected};
/// # /// #
/// # fn example<E>() -> Result<(), E> /// # fn example<E>() -> Result<(), E>
@@ -465,7 +464,10 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// # E: de::Error, /// # E: de::Error,
/// # { /// # {
/// # let v = true; /// # let v = true;
/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer")); /// return Err(de::Error::invalid_type(
/// Unexpected::Bool(v),
/// &"a negative integer",
/// ));
/// # } /// # }
/// ``` /// ```
pub trait Expected { pub trait Expected {
@@ -577,7 +579,7 @@ pub trait Deserialize<'de>: Sized {
/// from the input string, but a `from_reader` function may only deserialize /// from the input string, but a `from_reader` function may only deserialize
/// owned data. /// owned data.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{Deserialize, DeserializeOwned}; /// # use serde::de::{Deserialize, DeserializeOwned};
/// # use std::io::{Read, Result}; /// # use std::io::{Read, Result};
/// # /// #
@@ -616,7 +618,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// ///
/// The canonical API for stateless deserialization looks like this: /// The canonical API for stateless deserialization looks like this:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Deserialize; /// # use serde::Deserialize;
/// # /// #
/// # enum Error {} /// # enum Error {}
@@ -630,7 +632,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// Adjusting an API like this to support stateful deserialization is a matter /// Adjusting an API like this to support stateful deserialization is a matter
/// of accepting a seed as input: /// of accepting a seed as input:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::DeserializeSeed; /// # use serde::de::DeserializeSeed;
/// # /// #
/// # enum Error {} /// # enum Error {}
@@ -663,12 +665,11 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// into it. This requires stateful deserialization using the `DeserializeSeed` /// into it. This requires stateful deserialization using the `DeserializeSeed`
/// trait. /// trait.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
/// use std::fmt; /// use std::fmt;
/// use std::marker::PhantomData; /// use std::marker::PhantomData;
/// ///
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
///
/// // A DeserializeSeed implementation that uses stateful deserialization to /// // A DeserializeSeed implementation that uses stateful deserialization to
/// // append array elements onto the end of an existing vector. The preexisting /// // append array elements onto the end of an existing vector. The preexisting
/// // state ("seed") in this case is the Vec<T>. The `deserialize` method of /// // state ("seed") in this case is the Vec<T>. The `deserialize` method of
@@ -709,7 +710,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// { /// {
/// // Decrease the number of reallocations if there are many elements /// // Decrease the number of reallocations if there are many elements
/// if let Some(size_hint) = seq.size_hint() { /// if let Some(size_hint) = seq.size_hint() {
/// self.0.reserve(size_hint); /// self.0.reserve(size_hint);
/// } /// }
/// ///
/// // Visit each element in the inner array and push it onto /// // Visit each element in the inner array and push it onto
@@ -1158,7 +1159,7 @@ pub trait Deserializer<'de>: Sized {
/// human-readable one and binary formats like Postcard will prefer the /// human-readable one and binary formats like Postcard will prefer the
/// compact one. /// compact one.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::ops::Add; /// # use std::ops::Add;
/// # use std::str::FromStr; /// # use std::str::FromStr;
/// # /// #
@@ -1249,10 +1250,9 @@ pub trait Deserializer<'de>: Sized {
/// ///
/// # Example /// # Example
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::fmt;
/// #
/// # use serde::de::{self, Unexpected, Visitor}; /// # use serde::de::{self, Unexpected, Visitor};
/// # use std::fmt;
/// # /// #
/// /// A visitor that deserializes a long string - a string containing at least /// /// A visitor that deserializes a long string - a string containing at least
/// /// some minimum number of bytes. /// /// some minimum number of bytes.
@@ -1290,7 +1290,7 @@ pub trait Visitor<'de>: Sized {
/// "an integer between 0 and 64". The message should not be capitalized and /// "an integer between 0 and 64". The message should not be capitalized and
/// should not end with a period. /// should not end with a period.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::fmt; /// # use std::fmt;
/// # /// #
/// # struct S { /// # struct S {
@@ -2035,7 +2035,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following /// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed: /// `invalid_type` error should be constructed:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// # /// #
/// # struct X; /// # struct X;
@@ -2075,7 +2075,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following /// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed: /// `invalid_type` error should be constructed:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// # /// #
/// # struct X; /// # struct X;
@@ -2131,7 +2131,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following /// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed: /// `invalid_type` error should be constructed:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// # /// #
/// # struct X; /// # struct X;
@@ -2148,11 +2148,7 @@ pub trait VariantAccess<'de>: Sized {
/// # T: DeserializeSeed<'de>, /// # T: DeserializeSeed<'de>,
/// # { unimplemented!() } /// # { unimplemented!() }
/// # /// #
/// fn tuple_variant<V>( /// fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
/// self,
/// _len: usize,
/// _visitor: V,
/// ) -> Result<V::Value, Self::Error>
/// where /// where
/// V: Visitor<'de>, /// V: Visitor<'de>,
/// { /// {
@@ -2178,7 +2174,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following /// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed: /// `invalid_type` error should be constructed:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// # /// #
/// # struct X; /// # struct X;
@@ -2238,10 +2234,10 @@ pub trait VariantAccess<'de>: Sized {
/// ///
/// # Example /// # Example
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::de::{value, Deserialize, IntoDeserializer};
/// use serde_derive::Deserialize;
/// use std::str::FromStr; /// use std::str::FromStr;
/// use serde::Deserialize;
/// use serde::de::{value, IntoDeserializer};
/// ///
/// #[derive(Deserialize)] /// #[derive(Deserialize)]
/// enum Setting { /// enum Setting {
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn encode(c: char) -> Encode {
buf[3] = (code & 0x3F) as u8 | TAG_CONT; buf[3] = (code & 0x3F) as u8 | TAG_CONT;
0 0
}; };
Encode { buf: buf, pos: pos } Encode { buf, pos }
} }
pub struct Encode { pub struct Encode {
+17 -21
View File
@@ -1,10 +1,10 @@
//! Building blocks for deserializing basic values using the `IntoDeserializer` //! Building blocks for deserializing basic values using the `IntoDeserializer`
//! trait. //! trait.
//! //!
//! ```edition2018 //! ```edition2021
//! use serde::de::{value, Deserialize, IntoDeserializer};
//! use serde_derive::Deserialize;
//! use std::str::FromStr; //! use std::str::FromStr;
//! use serde::Deserialize;
//! use serde::de::{value, IntoDeserializer};
//! //!
//! #[derive(Deserialize)] //! #[derive(Deserialize)]
//! enum Setting { //! enum Setting {
@@ -251,7 +251,7 @@ macro_rules! primitive_deserializer {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(value: $ty) -> Self { pub fn new(value: $ty) -> Self {
$name { $name {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -330,7 +330,7 @@ impl<E> U32Deserializer<E> {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(value: u32) -> Self { pub fn new(value: u32) -> Self {
U32Deserializer { U32Deserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -419,7 +419,7 @@ impl<'a, E> StrDeserializer<'a, E> {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(value: &'a str) -> Self { pub fn new(value: &'a str) -> Self {
StrDeserializer { StrDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -498,7 +498,7 @@ impl<'de, E> BorrowedStrDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given string. /// Create a new borrowed deserializer from the given string.
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> { pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
BorrowedStrDeserializer { BorrowedStrDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -598,7 +598,7 @@ impl<E> StringDeserializer<E> {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(value: String) -> Self { pub fn new(value: String) -> Self {
StringDeserializer { StringDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -701,7 +701,7 @@ impl<'a, E> CowStrDeserializer<'a, E> {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(value: Cow<'a, str>) -> Self { pub fn new(value: Cow<'a, str>) -> Self {
CowStrDeserializer { CowStrDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -783,7 +783,7 @@ impl<'a, E> BytesDeserializer<'a, E> {
/// Create a new deserializer from the given bytes. /// Create a new deserializer from the given bytes.
pub fn new(value: &'a [u8]) -> Self { pub fn new(value: &'a [u8]) -> Self {
BytesDeserializer { BytesDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -842,7 +842,7 @@ impl<'de, E> BorrowedBytesDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given borrowed bytes. /// Create a new borrowed deserializer from the given borrowed bytes.
pub fn new(value: &'de [u8]) -> Self { pub fn new(value: &'de [u8]) -> Self {
BorrowedBytesDeserializer { BorrowedBytesDeserializer {
value: value, value,
marker: PhantomData, marker: PhantomData,
} }
} }
@@ -1053,7 +1053,7 @@ pub struct SeqAccessDeserializer<A> {
impl<A> SeqAccessDeserializer<A> { impl<A> SeqAccessDeserializer<A> {
/// Construct a new `SeqAccessDeserializer<A>`. /// Construct a new `SeqAccessDeserializer<A>`.
pub fn new(seq: A) -> Self { pub fn new(seq: A) -> Self {
SeqAccessDeserializer { seq: seq } SeqAccessDeserializer { seq }
} }
} }
@@ -1454,7 +1454,7 @@ pub struct MapAccessDeserializer<A> {
impl<A> MapAccessDeserializer<A> { impl<A> MapAccessDeserializer<A> {
/// Construct a new `MapAccessDeserializer<A>`. /// Construct a new `MapAccessDeserializer<A>`.
pub fn new(map: A) -> Self { pub fn new(map: A) -> Self {
MapAccessDeserializer { map: map } MapAccessDeserializer { map }
} }
} }
@@ -1519,7 +1519,7 @@ pub struct EnumAccessDeserializer<A> {
impl<A> EnumAccessDeserializer<A> { impl<A> EnumAccessDeserializer<A> {
/// Construct a new `EnumAccessDeserializer<A>`. /// Construct a new `EnumAccessDeserializer<A>`.
pub fn new(access: A) -> Self { pub fn new(access: A) -> Self {
EnumAccessDeserializer { access: access } EnumAccessDeserializer { access }
} }
} }
@@ -1613,7 +1613,7 @@ mod private {
} }
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> { pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
MapAsEnum { map: map } MapAsEnum { map }
} }
impl<'de, A> VariantAccess<'de> for MapAsEnum<A> impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
@@ -1637,10 +1637,7 @@ mod private {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
self.map.next_value_seed(SeedTupleVariant { self.map.next_value_seed(SeedTupleVariant { len, visitor })
len: len,
visitor: visitor,
})
} }
fn struct_variant<V>( fn struct_variant<V>(
@@ -1651,8 +1648,7 @@ mod private {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
self.map self.map.next_value_seed(SeedStructVariant { visitor })
.next_value_seed(SeedStructVariant { visitor: visitor })
} }
} }
+3 -3
View File
@@ -9,7 +9,7 @@
/// or do not target platforms that lack 128-bit integers, do not need to /// or do not target platforms that lack 128-bit integers, do not need to
/// bother with this macro and may assume support for 128-bit integers. /// bother with this macro and may assume support for 128-bit integers.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::__private::doc::Error; /// # use serde::__private::doc::Error;
/// # /// #
/// # struct MySerializer; /// # struct MySerializer;
@@ -50,7 +50,7 @@
/// When Serde is built with support for 128-bit integers, this macro expands /// When Serde is built with support for 128-bit integers, this macro expands
/// transparently into just the input tokens. /// transparently into just the input tokens.
/// ///
/// ```edition2018 /// ```edition2021
/// macro_rules! serde_if_integer128 { /// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => { /// ($($tt:tt)*) => {
/// $($tt)* /// $($tt)*
@@ -61,7 +61,7 @@
/// When built without support for 128-bit integers, this macro expands to /// When built without support for 128-bit integers, this macro expands to
/// nothing. /// nothing.
/// ///
/// ```edition2018 /// ```edition2021
/// macro_rules! serde_if_integer128 { /// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => {}; /// ($($tt:tt)*) => {};
/// } /// }
+2 -2
View File
@@ -93,7 +93,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.159")] #![doc(html_root_url = "https://docs.rs/serde/1.0.167")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
@@ -180,7 +180,7 @@ mod lib {
pub use self::core::fmt::{self, Debug, Display}; pub use self::core::fmt::{self, Debug, Display};
pub use self::core::marker::{self, PhantomData}; pub use self::core::marker::{self, PhantomData};
pub use self::core::num::Wrapping; pub use self::core::num::Wrapping;
pub use self::core::ops::Range; pub use self::core::ops::{Range, RangeFrom, RangeTo};
pub use self::core::option::{self, Option}; pub use self::core::option::{self, Option};
pub use self::core::result::{self, Result}; pub use self::core::result::{self, Result};
+4 -5
View File
@@ -11,7 +11,7 @@
/// input. This requires repetitive implementations of all the [`Deserializer`] /// input. This requires repetitive implementations of all the [`Deserializer`]
/// trait methods. /// trait methods.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::forward_to_deserialize_any; /// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor}; /// # use serde::de::{value, Deserializer, Visitor};
/// # /// #
@@ -47,7 +47,7 @@
/// methods so that they forward directly to [`Deserializer::deserialize_any`]. /// methods so that they forward directly to [`Deserializer::deserialize_any`].
/// You can choose which methods to forward. /// You can choose which methods to forward.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::forward_to_deserialize_any; /// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor}; /// # use serde::de::{value, Deserializer, Visitor};
/// # /// #
@@ -78,11 +78,10 @@
/// called `V`. A different type parameter and a different lifetime can be /// called `V`. A different type parameter and a different lifetime can be
/// specified explicitly if necessary. /// specified explicitly if necessary.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # use serde::forward_to_deserialize_any; /// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor}; /// # use serde::de::{value, Deserializer, Visitor};
/// # use std::marker::PhantomData;
/// # /// #
/// # struct MyDeserializer<V>(PhantomData<V>); /// # struct MyDeserializer<V>(PhantomData<V>);
/// # /// #
+75 -145
View File
@@ -518,7 +518,7 @@ mod content {
impl<'de> TagOrContentVisitor<'de> { impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self { fn new(name: &'static str) -> Self {
TagOrContentVisitor { TagOrContentVisitor {
name: name, name,
value: PhantomData, value: PhantomData,
} }
} }
@@ -797,51 +797,29 @@ mod content {
/// Used by generated code to deserialize an internally tagged enum. /// Used by generated code to deserialize an internally tagged enum.
/// ///
/// Not public API. /// Not public API.
pub struct TaggedContent<'de, T> { pub struct TaggedContentVisitor<T> {
pub tag: T,
pub content: Content<'de>,
}
/// Not public API.
pub struct TaggedContentVisitor<'de, T> {
tag_name: &'static str, tag_name: &'static str,
expecting: &'static str, expecting: &'static str,
value: PhantomData<TaggedContent<'de, T>>, value: PhantomData<T>,
} }
impl<'de, T> TaggedContentVisitor<'de, T> { impl<T> TaggedContentVisitor<T> {
/// Visitor for the content of an internally tagged enum with the given /// Visitor for the content of an internally tagged enum with the given
/// tag name. /// tag name.
pub fn new(name: &'static str, expecting: &'static str) -> Self { pub fn new(name: &'static str, expecting: &'static str) -> Self {
TaggedContentVisitor { TaggedContentVisitor {
tag_name: name, tag_name: name,
expecting: expecting, expecting,
value: PhantomData, value: PhantomData,
} }
} }
} }
impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<'de, T> impl<'de, T> Visitor<'de> for TaggedContentVisitor<T>
where where
T: Deserialize<'de>, T: Deserialize<'de>,
{ {
type Value = TaggedContent<'de, T>; type Value = (T, Content<'de>);
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
// Internally tagged enums are only supported in self-describing
// formats.
deserializer.deserialize_any(self)
}
}
impl<'de, T> Visitor<'de> for TaggedContentVisitor<'de, T>
where
T: Deserialize<'de>,
{
type Value = TaggedContent<'de, T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.expecting) fmt.write_str(self.expecting)
@@ -858,10 +836,7 @@ mod content {
} }
}; };
let rest = de::value::SeqAccessDeserializer::new(seq); let rest = de::value::SeqAccessDeserializer::new(seq);
Ok(TaggedContent { Ok((tag, try!(Content::deserialize(rest))))
tag: tag,
content: try!(Content::deserialize(rest)),
})
} }
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
@@ -886,10 +861,7 @@ mod content {
} }
match tag { match tag {
None => Err(de::Error::missing_field(self.tag_name)), None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => Ok(TaggedContent { Some(tag) => Ok((tag, Content::Map(vec))),
tag: tag,
content: Content::Map(vec),
}),
} }
} }
} }
@@ -982,9 +954,16 @@ mod content {
where where
E: de::Error, E: de::Error,
{ {
if field == self.tag { self.visit_bytes(field.as_bytes())
}
fn visit_bytes<E>(self, field: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag.as_bytes() {
Ok(TagContentOtherField::Tag) Ok(TagContentOtherField::Tag)
} else if field == self.content { } else if field == self.content.as_bytes() {
Ok(TagContentOtherField::Content) Ok(TagContentOtherField::Content)
} else { } else {
Ok(TagContentOtherField::Other) Ok(TagContentOtherField::Other)
@@ -1457,7 +1436,7 @@ mod content {
/// private API, don't use /// private API, don't use
pub fn new(content: Content<'de>) -> Self { pub fn new(content: Content<'de>) -> Self {
ContentDeserializer { ContentDeserializer {
content: content, content,
err: PhantomData, err: PhantomData,
} }
} }
@@ -1478,8 +1457,8 @@ mod content {
{ {
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> { pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
EnumDeserializer { EnumDeserializer {
variant: variant, variant,
value: value, value,
err: PhantomData, err: PhantomData,
} }
} }
@@ -2135,8 +2114,8 @@ mod content {
}; };
visitor.visit_enum(EnumRefDeserializer { visitor.visit_enum(EnumRefDeserializer {
variant: variant, variant,
value: value, value,
err: PhantomData, err: PhantomData,
}) })
} }
@@ -2180,12 +2159,20 @@ mod content {
/// private API, don't use /// private API, don't use
pub fn new(content: &'a Content<'de>) -> Self { pub fn new(content: &'a Content<'de>) -> Self {
ContentRefDeserializer { ContentRefDeserializer {
content: content, content,
err: PhantomData, err: PhantomData,
} }
} }
} }
impl<'a, 'de: 'a, E> Copy for ContentRefDeserializer<'a, 'de, E> {}
impl<'a, 'de: 'a, E> Clone for ContentRefDeserializer<'a, 'de, E> {
fn clone(&self) -> Self {
*self
}
}
struct EnumRefDeserializer<'a, 'de: 'a, E> struct EnumRefDeserializer<'a, 'de: 'a, E>
where where
E: de::Error, E: de::Error,
@@ -2481,8 +2468,8 @@ mod content {
/// Not public API. /// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
InternallyTaggedUnitVisitor { InternallyTaggedUnitVisitor {
type_name: type_name, type_name,
variant_name: variant_name, variant_name,
} }
} }
} }
@@ -2526,8 +2513,8 @@ mod content {
/// Not public API. /// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
UntaggedUnitVisitor { UntaggedUnitVisitor {
type_name: type_name, type_name,
variant_name: variant_name, variant_name,
} }
} }
} }
@@ -2731,11 +2718,7 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatInternallyTaggedAccess { self.deserialize_map(visitor)
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
} }
fn deserialize_enum<V>( fn deserialize_enum<V>(
@@ -2747,17 +2730,8 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
for item in self.0.iter_mut() { for entry in self.0 {
// items in the vector are nulled out when used. So we can only use if let Some((key, value)) = flat_map_take_entry(entry, variants) {
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
};
if use_item {
let (key, value) = item.take().unwrap();
return visitor.visit_enum(EnumDeserializer::new(key, Some(value))); return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
} }
} }
@@ -2772,7 +2746,11 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatMapAccess::new(self.0.iter())) visitor.visit_map(FlatMapAccess {
iter: self.0.iter(),
pending_content: None,
_marker: PhantomData,
})
} }
fn deserialize_struct<V>( fn deserialize_struct<V>(
@@ -2784,7 +2762,12 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields)) visitor.visit_map(FlatStructAccess {
iter: self.0.iter_mut(),
pending_content: None,
fields,
_marker: PhantomData,
})
} }
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
@@ -2838,25 +2821,12 @@ where
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> { struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<&'a Content<'de>>, pending_content: Option<&'a Content<'de>>,
_marker: PhantomData<E>, _marker: PhantomData<E>,
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where where
@@ -2871,6 +2841,10 @@ where
for item in &mut self.iter { for item in &mut self.iter {
// Items in the vector are nulled out when used by a struct. // Items in the vector are nulled out when used by a struct.
if let Some((ref key, ref content)) = *item { if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending_content = Some(content); self.pending_content = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
} }
@@ -2890,28 +2864,13 @@ where
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatStructAccess<'a, 'de: 'a, E> { struct FlatStructAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>, pending_content: Option<Content<'de>>,
fields: &'static [&'static str], fields: &'static [&'static str],
_marker: PhantomData<E>, _marker: PhantomData<E>,
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: &'static [&'static str],
) -> FlatStructAccess<'a, 'de, E> {
FlatStructAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E> impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
where where
@@ -2923,17 +2882,8 @@ where
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
while let Some(item) = self.iter.next() { for entry in self.iter.by_ref() {
// items in the vector are nulled out when used. So we can only use if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)),
};
if use_item {
let (key, content) = item.take().unwrap();
self.pending_content = Some(content); self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some); return seed.deserialize(ContentDeserializer::new(key)).map(Some);
} }
@@ -2952,44 +2902,24 @@ where
} }
} }
/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the
/// field name matches any of the recognized ones.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> { fn flat_map_take_entry<'de>(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, entry: &mut Option<(Content<'de>, Content<'de>)>,
pending: Option<&'a Content<'de>>, recognized: &[&str],
_marker: PhantomData<E>, ) -> Option<(Content<'de>, Content<'de>)> {
} // Entries in the FlatMapDeserializer buffer are nulled out as they get
// claimed for deserialization. We only use an entry if it is still present
// and if the field is one recognized by the current data structure.
let is_recognized = match entry {
None => false,
Some((k, _v)) => k.as_str().map_or(false, |name| recognized.contains(&name)),
};
#[cfg(any(feature = "std", feature = "alloc"))] if is_recognized {
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E> entry.take()
where } else {
E: Error, None
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
for item in &mut self.iter {
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
} }
} }
+18 -18
View File
@@ -27,10 +27,10 @@ where
T: Serialize, T: Serialize,
{ {
value.serialize(TaggedSerializer { value.serialize(TaggedSerializer {
type_ident: type_ident, type_ident,
variant_ident: variant_ident, variant_ident,
tag: tag, tag,
variant_name: variant_name, variant_name,
delegate: serializer, delegate: serializer,
}) })
} }
@@ -350,8 +350,8 @@ mod content {
impl<M> SerializeTupleVariantAsMapValue<M> { impl<M> SerializeTupleVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self { pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeTupleVariantAsMapValue { SerializeTupleVariantAsMapValue {
map: map, map,
name: name, name,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
} }
} }
@@ -390,8 +390,8 @@ mod content {
impl<M> SerializeStructVariantAsMapValue<M> { impl<M> SerializeStructVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self { pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeStructVariantAsMapValue { SerializeStructVariantAsMapValue {
map: map, map,
name: name, name,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
} }
} }
@@ -711,7 +711,7 @@ mod content {
len: usize, len: usize,
) -> Result<Self::SerializeTupleStruct, E> { ) -> Result<Self::SerializeTupleStruct, E> {
Ok(SerializeTupleStruct { Ok(SerializeTupleStruct {
name: name, name,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
error: PhantomData, error: PhantomData,
}) })
@@ -725,9 +725,9 @@ mod content {
len: usize, len: usize,
) -> Result<Self::SerializeTupleVariant, E> { ) -> Result<Self::SerializeTupleVariant, E> {
Ok(SerializeTupleVariant { Ok(SerializeTupleVariant {
name: name, name,
variant_index: variant_index, variant_index,
variant: variant, variant,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
error: PhantomData, error: PhantomData,
}) })
@@ -747,7 +747,7 @@ mod content {
len: usize, len: usize,
) -> Result<Self::SerializeStruct, E> { ) -> Result<Self::SerializeStruct, E> {
Ok(SerializeStruct { Ok(SerializeStruct {
name: name, name,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
error: PhantomData, error: PhantomData,
}) })
@@ -761,9 +761,9 @@ mod content {
len: usize, len: usize,
) -> Result<Self::SerializeStructVariant, E> { ) -> Result<Self::SerializeStructVariant, E> {
Ok(SerializeStructVariant { Ok(SerializeStructVariant {
name: name, name,
variant_index: variant_index, variant_index,
variant: variant, variant,
fields: Vec::with_capacity(len), fields: Vec::with_capacity(len),
error: PhantomData, error: PhantomData,
}) })
@@ -1273,8 +1273,8 @@ where
{ {
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> { fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue { FlatMapSerializeStructVariantAsMapValue {
map: map, map,
name: name, name,
fields: Vec::new(), fields: Vec::new(),
} }
} }
+3 -2
View File
@@ -17,8 +17,9 @@ macro_rules! fmt_primitives {
}; };
} }
/// ```edition2018 /// ```edition2021
/// use serde::Serialize; /// use serde::ser::Serialize;
/// use serde_derive::Serialize;
/// use std::fmt::{self, Display}; /// use std::fmt::{self, Display};
/// ///
/// #[derive(Serialize)] /// #[derive(Serialize)]
+35 -1
View File
@@ -257,6 +257,23 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeFrom<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeFrom", 1));
try!(state.serialize_field("start", &self.start));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(not(no_range_inclusive))] #[cfg(not(no_range_inclusive))]
impl<Idx> Serialize for RangeInclusive<Idx> impl<Idx> Serialize for RangeInclusive<Idx>
where where
@@ -276,6 +293,23 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeTo<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeTo", 1));
try!(state.serialize_field("end", &self.end));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))] #[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))]
impl<T> Serialize for Bound<T> impl<T> Serialize for Bound<T>
where where
@@ -713,7 +747,7 @@ impl Serialize for net::IpAddr {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
const DEC_DIGITS_LUT: &'static [u8] = b"\ const DEC_DIGITS_LUT: &[u8] = b"\
0001020304050607080910111213141516171819\ 0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\ 2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\ 4041424344454647484950515253545556575859\
+1 -1
View File
@@ -15,7 +15,7 @@ use ser::{
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`], /// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`]. /// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::ser::{Serializer, Impossible}; /// # use serde::ser::{Serializer, Impossible};
/// # use serde::__private::doc::Error; /// # use serde::__private::doc::Error;
/// # /// #
+60 -64
View File
@@ -149,7 +149,7 @@ macro_rules! declare_error_trait {
/// For example, a filesystem [`Path`] may refuse to serialize /// For example, a filesystem [`Path`] may refuse to serialize
/// itself if it contains invalid UTF-8 data. /// itself if it contains invalid UTF-8 data.
/// ///
/// ```edition2018 /// ```edition2021
/// # struct Path; /// # struct Path;
/// # /// #
/// # impl Path { /// # impl Path {
@@ -221,7 +221,7 @@ pub trait Serialize {
/// See the [Implementing `Serialize`] section of the manual for more /// See the [Implementing `Serialize`] section of the manual for more
/// information about how to implement this method. /// information about how to implement this method.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// use serde::ser::{Serialize, SerializeStruct, Serializer};
/// ///
/// struct Person { /// struct Person {
@@ -388,7 +388,7 @@ pub trait Serializer: Sized {
/// Serialize a `bool` value. /// Serialize a `bool` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -410,7 +410,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and /// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`. /// forward to `serialize_i64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -432,7 +432,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and /// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`. /// forward to `serialize_i64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -454,7 +454,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and /// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`. /// forward to `serialize_i64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -472,7 +472,7 @@ pub trait Serializer: Sized {
/// Serialize an `i64` value. /// Serialize an `i64` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -491,7 +491,7 @@ pub trait Serializer: Sized {
serde_if_integer128! { serde_if_integer128! {
/// Serialize an `i128` value. /// Serialize an `i128` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -520,7 +520,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and /// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`. /// forward to `serialize_u64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -542,7 +542,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and /// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`. /// forward to `serialize_u64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -564,7 +564,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and /// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`. /// forward to `serialize_u64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -582,7 +582,7 @@ pub trait Serializer: Sized {
/// Serialize a `u64` value. /// Serialize a `u64` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -601,7 +601,7 @@ pub trait Serializer: Sized {
serde_if_integer128! { serde_if_integer128! {
/// Serialize a `u128` value. /// Serialize a `u128` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -630,7 +630,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `f64` and /// reasonable implementation would be to cast the value to `f64` and
/// forward to `serialize_f64`. /// forward to `serialize_f64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -648,7 +648,7 @@ pub trait Serializer: Sized {
/// Serialize an `f64` value. /// Serialize an `f64` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -669,7 +669,7 @@ pub trait Serializer: Sized {
/// If the format does not support characters, it is reasonable to serialize /// If the format does not support characters, it is reasonable to serialize
/// it as a single element `str` or a `u32`. /// it as a single element `str` or a `u32`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -687,7 +687,7 @@ pub trait Serializer: Sized {
/// Serialize a `&str`. /// Serialize a `&str`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -711,7 +711,7 @@ pub trait Serializer: Sized {
/// `serialize_seq`. If forwarded, the implementation looks usually just /// `serialize_seq`. If forwarded, the implementation looks usually just
/// like this: /// like this:
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::ser::{Serializer, SerializeSeq}; /// # use serde::ser::{Serializer, SerializeSeq};
/// # use serde::__private::doc::Error; /// # use serde::__private::doc::Error;
/// # /// #
@@ -740,7 +740,7 @@ pub trait Serializer: Sized {
/// Serialize a [`None`] value. /// Serialize a [`None`] value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Serializer}; /// # use serde::{Serialize, Serializer};
/// # /// #
/// # enum Option<T> { /// # enum Option<T> {
@@ -773,7 +773,7 @@ pub trait Serializer: Sized {
/// Serialize a [`Some(T)`] value. /// Serialize a [`Some(T)`] value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Serializer}; /// # use serde::{Serialize, Serializer};
/// # /// #
/// # enum Option<T> { /// # enum Option<T> {
@@ -808,7 +808,7 @@ pub trait Serializer: Sized {
/// Serialize a `()` value. /// Serialize a `()` value.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::Serializer; /// # use serde::Serializer;
/// # /// #
/// # serde::__private_serialize!(); /// # serde::__private_serialize!();
@@ -828,7 +828,7 @@ pub trait Serializer: Sized {
/// ///
/// A reasonable implementation would be to forward to `serialize_unit`. /// A reasonable implementation would be to forward to `serialize_unit`.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// ///
/// struct Nothing; /// struct Nothing;
@@ -850,7 +850,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, and the `variant` is the name of the /// this variant within the enum, and the `variant` is the name of the
/// variant. /// variant.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// ///
/// enum E { /// enum E {
@@ -883,7 +883,7 @@ pub trait Serializer: Sized {
/// wrappers around the data they contain. A reasonable implementation would /// wrappers around the data they contain. A reasonable implementation would
/// be to forward to `value.serialize(self)`. /// be to forward to `value.serialize(self)`.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// ///
/// struct Millimeters(u8); /// struct Millimeters(u8);
@@ -911,7 +911,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, and the `variant` is the name of the /// this variant within the enum, and the `variant` is the name of the
/// variant. The `value` is the data contained within this newtype variant. /// variant. The `value` is the data contained within this newtype variant.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// ///
/// enum E { /// enum E {
@@ -949,7 +949,7 @@ pub trait Serializer: Sized {
/// not be computable before the sequence is iterated. Some serializers only /// not be computable before the sequence is iterated. Some serializers only
/// support sequences whose length is known up front. /// support sequences whose length is known up front.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData; /// # use std::marker::PhantomData;
/// # /// #
/// # struct Vec<T>(PhantomData<T>); /// # struct Vec<T>(PhantomData<T>);
@@ -962,14 +962,14 @@ pub trait Serializer: Sized {
/// # /// #
/// # impl<'a, T> IntoIterator for &'a Vec<T> { /// # impl<'a, T> IntoIterator for &'a Vec<T> {
/// # type Item = &'a T; /// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>; /// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// # /// #
/// # fn into_iter(self) -> Self::IntoIter { /// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # } /// # }
/// # /// #
/// use serde::ser::{Serialize, Serializer, SerializeSeq}; /// use serde::ser::{Serialize, SerializeSeq, Serializer};
/// ///
/// impl<T> Serialize for Vec<T> /// impl<T> Serialize for Vec<T>
/// where /// where
@@ -994,8 +994,8 @@ pub trait Serializer: Sized {
/// This call must be followed by zero or more calls to `serialize_element`, /// This call must be followed by zero or more calls to `serialize_element`,
/// then a call to `end`. /// then a call to `end`.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, Serializer, SerializeTuple}; /// use serde::ser::{Serialize, SerializeTuple, Serializer};
/// ///
/// # mod fool { /// # mod fool {
/// # trait Serialize {} /// # trait Serialize {}
@@ -1024,7 +1024,7 @@ pub trait Serializer: Sized {
/// } /// }
/// ``` /// ```
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeTuple, Serializer}; /// use serde::ser::{Serialize, SerializeTuple, Serializer};
/// ///
/// const VRAM_SIZE: usize = 386; /// const VRAM_SIZE: usize = 386;
@@ -1052,7 +1052,7 @@ pub trait Serializer: Sized {
/// The `name` is the name of the tuple struct and the `len` is the number /// The `name` is the name of the tuple struct and the `len` is the number
/// of data fields that will be serialized. /// of data fields that will be serialized.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
/// ///
/// struct Rgb(u8, u8, u8); /// struct Rgb(u8, u8, u8);
@@ -1084,7 +1084,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, the `variant` is the name of the variant, /// this variant within the enum, the `variant` is the name of the variant,
/// and the `len` is the number of data fields that will be serialized. /// and the `len` is the number of data fields that will be serialized.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer};
/// ///
/// enum E { /// enum E {
@@ -1130,7 +1130,7 @@ pub trait Serializer: Sized {
/// be computable before the map is iterated. Some serializers only support /// be computable before the map is iterated. Some serializers only support
/// maps whose length is known up front. /// maps whose length is known up front.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData; /// # use std::marker::PhantomData;
/// # /// #
/// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>); /// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>);
@@ -1143,14 +1143,14 @@ pub trait Serializer: Sized {
/// # /// #
/// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> { /// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> {
/// # type Item = (&'a K, &'a V); /// # type Item = (&'a K, &'a V);
/// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>; /// # type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)>>;
/// # /// #
/// # fn into_iter(self) -> Self::IntoIter { /// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # } /// # }
/// # /// #
/// use serde::ser::{Serialize, Serializer, SerializeMap}; /// use serde::ser::{Serialize, SerializeMap, Serializer};
/// ///
/// impl<K, V> Serialize for HashMap<K, V> /// impl<K, V> Serialize for HashMap<K, V>
/// where /// where
@@ -1178,7 +1178,7 @@ pub trait Serializer: Sized {
/// The `name` is the name of the struct and the `len` is the number of /// The `name` is the name of the struct and the `len` is the number of
/// data fields that will be serialized. /// data fields that will be serialized.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// use serde::ser::{Serialize, SerializeStruct, Serializer};
/// ///
/// struct Rgb { /// struct Rgb {
@@ -1214,7 +1214,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, the `variant` is the name of the variant, /// this variant within the enum, the `variant` is the name of the variant,
/// and the `len` is the number of data fields that will be serialized. /// and the `len` is the number of data fields that will be serialized.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; /// use serde::ser::{Serialize, SerializeStructVariant, Serializer};
/// ///
/// enum E { /// enum E {
@@ -1256,7 +1256,7 @@ pub trait Serializer: Sized {
/// using [`serialize_seq`]. Implementors should not need to override this /// using [`serialize_seq`]. Implementors should not need to override this
/// method. /// method.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// ///
/// struct SecretlyOneHigher { /// struct SecretlyOneHigher {
@@ -1304,7 +1304,7 @@ pub trait Serializer: Sized {
/// using [`serialize_map`]. Implementors should not need to override this /// using [`serialize_map`]. Implementors should not need to override this
/// method. /// method.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Serialize, Serializer}; /// use serde::{Serialize, Serializer};
/// use std::collections::BTreeSet; /// use std::collections::BTreeSet;
/// ///
@@ -1355,7 +1355,7 @@ pub trait Serializer: Sized {
/// delegates to [`serialize_str`]. Serializers are encouraged to provide a /// delegates to [`serialize_str`]. Serializers are encouraged to provide a
/// more efficient implementation if possible. /// more efficient implementation if possible.
/// ///
/// ```edition2018 /// ```edition2021
/// # struct DateTime; /// # struct DateTime;
/// # /// #
/// # impl DateTime { /// # impl DateTime {
@@ -1370,9 +1370,7 @@ pub trait Serializer: Sized {
/// where /// where
/// S: Serializer, /// S: Serializer,
/// { /// {
/// serializer.collect_str(&format_args!("{:?}{:?}", /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset()))
/// self.naive_local(),
/// self.offset()))
/// } /// }
/// } /// }
/// ``` /// ```
@@ -1393,7 +1391,7 @@ pub trait Serializer: Sized {
/// of this method. If no more sensible behavior is possible, the /// of this method. If no more sensible behavior is possible, the
/// implementation is expected to return an error. /// implementation is expected to return an error.
/// ///
/// ```edition2018 /// ```edition2021
/// # struct DateTime; /// # struct DateTime;
/// # /// #
/// # impl DateTime { /// # impl DateTime {
@@ -1408,9 +1406,7 @@ pub trait Serializer: Sized {
/// where /// where
/// S: Serializer, /// S: Serializer,
/// { /// {
/// serializer.collect_str(&format_args!("{:?}{:?}", /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset()))
/// self.naive_local(),
/// self.offset()))
/// } /// }
/// } /// }
/// ``` /// ```
@@ -1428,7 +1424,7 @@ pub trait Serializer: Sized {
/// human-readable one and binary formats like Postcard will prefer the /// human-readable one and binary formats like Postcard will prefer the
/// compact one. /// compact one.
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::fmt::{self, Display}; /// # use std::fmt::{self, Display};
/// # /// #
/// # struct Timestamp; /// # struct Timestamp;
@@ -1477,7 +1473,7 @@ pub trait Serializer: Sized {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData; /// # use std::marker::PhantomData;
/// # /// #
/// # struct Vec<T>(PhantomData<T>); /// # struct Vec<T>(PhantomData<T>);
@@ -1490,13 +1486,13 @@ pub trait Serializer: Sized {
/// # /// #
/// # impl<'a, T> IntoIterator for &'a Vec<T> { /// # impl<'a, T> IntoIterator for &'a Vec<T> {
/// # type Item = &'a T; /// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>; /// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// # fn into_iter(self) -> Self::IntoIter { /// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # } /// # }
/// # /// #
/// use serde::ser::{Serialize, Serializer, SerializeSeq}; /// use serde::ser::{Serialize, SerializeSeq, Serializer};
/// ///
/// impl<T> Serialize for Vec<T> /// impl<T> Serialize for Vec<T>
/// where /// where
@@ -1541,8 +1537,8 @@ pub trait SerializeSeq {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, Serializer, SerializeTuple}; /// use serde::ser::{Serialize, SerializeTuple, Serializer};
/// ///
/// # mod fool { /// # mod fool {
/// # trait Serialize {} /// # trait Serialize {}
@@ -1571,7 +1567,7 @@ pub trait SerializeSeq {
/// } /// }
/// ``` /// ```
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData; /// # use std::marker::PhantomData;
/// # /// #
/// # struct Array<T>(PhantomData<T>); /// # struct Array<T>(PhantomData<T>);
@@ -1584,13 +1580,13 @@ pub trait SerializeSeq {
/// # /// #
/// # impl<'a, T> IntoIterator for &'a Array<T> { /// # impl<'a, T> IntoIterator for &'a Array<T> {
/// # type Item = &'a T; /// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>; /// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// # fn into_iter(self) -> Self::IntoIter { /// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # } /// # }
/// # /// #
/// use serde::ser::{Serialize, Serializer, SerializeTuple}; /// use serde::ser::{Serialize, SerializeTuple, Serializer};
/// ///
/// # mod fool { /// # mod fool {
/// # trait Serialize {} /// # trait Serialize {}
@@ -1641,7 +1637,7 @@ pub trait SerializeTuple {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
/// ///
/// struct Rgb(u8, u8, u8); /// struct Rgb(u8, u8, u8);
@@ -1686,7 +1682,7 @@ pub trait SerializeTupleStruct {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer};
/// ///
/// enum E { /// enum E {
@@ -1744,7 +1740,7 @@ pub trait SerializeTupleVariant {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// # use std::marker::PhantomData; /// # use std::marker::PhantomData;
/// # /// #
/// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>); /// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>);
@@ -1757,14 +1753,14 @@ pub trait SerializeTupleVariant {
/// # /// #
/// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> { /// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> {
/// # type Item = (&'a K, &'a V); /// # type Item = (&'a K, &'a V);
/// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>; /// # type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)>>;
/// # /// #
/// # fn into_iter(self) -> Self::IntoIter { /// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// # } /// # }
/// # /// #
/// use serde::ser::{Serialize, Serializer, SerializeMap}; /// use serde::ser::{Serialize, SerializeMap, Serializer};
/// ///
/// impl<K, V> Serialize for HashMap<K, V> /// impl<K, V> Serialize for HashMap<K, V>
/// where /// where
@@ -1855,7 +1851,7 @@ pub trait SerializeMap {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// use serde::ser::{Serialize, SerializeStruct, Serializer};
/// ///
/// struct Rgb { /// struct Rgb {
@@ -1915,7 +1911,7 @@ pub trait SerializeStruct {
/// ///
/// # Example use /// # Example use
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; /// use serde::ser::{Serialize, SerializeStructVariant, Serializer};
/// ///
/// enum E { /// enum E {
+3 -3
View File
@@ -9,7 +9,7 @@ use lib::{Debug, Display};
/// generally provide their error types with a `std::error::Error` impl /// generally provide their error types with a `std::error::Error` impl
/// directly: /// directly:
/// ///
/// ```edition2018 /// ```edition2021
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct MySerError {...} /// struct MySerError {...}
/// ///
@@ -29,7 +29,7 @@ use lib::{Debug, Display};
/// std = ["serde/std"] /// std = ["serde/std"]
/// ``` /// ```
/// ///
/// ```edition2018 /// ```edition2021
/// #[cfg(feature = "std")] /// #[cfg(feature = "std")]
/// impl std::error::Error for MySerError {} /// impl std::error::Error for MySerError {}
/// ``` /// ```
@@ -37,7 +37,7 @@ use lib::{Debug, Display};
/// ... or else provide the std Error impl unconditionally via Serde's /// ... or else provide the std Error impl unconditionally via Serde's
/// re-export: /// re-export:
/// ///
/// ```edition2018 /// ```edition2021
/// impl serde::ser::StdError for MySerError {} /// impl serde::ser::StdError for MySerError {}
/// ``` /// ```
pub trait Error: Debug + Display { pub trait Error: Debug + Display {
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+3 -3
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.159" # remember to update html_root_url version = "1.0.167" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"] categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html" documentation = "https://serde.rs/derive.html"
homepage = "https://serde.rs" homepage = "https://serde.rs"
@@ -24,7 +24,7 @@ proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = "2.0.3" syn = "2.0.21"
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
-38
View File
@@ -1,38 +0,0 @@
use std::env;
use std::process::Command;
use std::str;
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// Underscore const names stabilized in Rust 1.37:
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
if minor < 37 {
println!("cargo:rustc-cfg=no_underscore_consts");
}
// The ptr::addr_of! macro stabilized in Rust 1.51:
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
if minor < 51 {
println!("cargo:rustc-cfg=no_ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+1 -1
View File
@@ -259,7 +259,7 @@ pub fn with_bound(
}; };
match &cont.data { match &cont.data {
Data::Enum(variants) => { Data::Enum(variants) => {
for variant in variants.iter() { for variant in variants {
let relevant_fields = variant let relevant_fields = variant
.fields .fields
.iter() .iter()
+265 -236
View File
@@ -15,9 +15,7 @@ use this;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ptr; use std::ptr;
pub fn expand_derive_deserialize( pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input); replace_receiver(input);
let ctxt = Ctxt::new(); let ctxt = Ctxt::new();
@@ -69,8 +67,6 @@ pub fn expand_derive_deserialize(
Ok(dummy::wrap_in_const( Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(), cont.attrs.custom_serde_path(),
"DESERIALIZE",
ident,
impl_block, impl_block,
)) ))
} }
@@ -291,10 +287,10 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
match &cont.data { match &cont.data {
Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs), Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, fields) => { Data::Struct(Style::Struct, fields) => {
deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) deserialize_struct(params, fields, &cont.attrs, StructForm::Struct)
} }
Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
deserialize_tuple(None, params, fields, &cont.attrs, None) deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple)
} }
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
} }
@@ -419,6 +415,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
let expecting = cattrs.expecting().unwrap_or(&expecting); let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor; struct __Visitor;
impl<'de> _serde::de::Visitor<'de> for __Visitor { impl<'de> _serde::de::Visitor<'de> for __Visitor {
@@ -441,21 +438,34 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
} }
} }
enum TupleForm<'a> {
Tuple,
/// Contains a variant name
ExternallyTagged(&'a syn::Ident),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
Untagged(&'a syn::Ident, TokenStream),
}
fn deserialize_tuple( fn deserialize_tuple(
variant_ident: Option<&syn::Ident>,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<TokenStream>, form: TupleForm,
) -> Fragment { ) -> Fragment {
assert!(!cattrs.has_flatten());
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type; let this_type = &params.this_type;
let this_value = &params.this_value; let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params); split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
// If there are getters (implying private fields), construct the local type // 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 // and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly. // getters then construct the target type directly.
@@ -466,23 +476,27 @@ fn deserialize_tuple(
quote!(#this_value) quote!(#this_value)
}; };
let is_enum = variant_ident.is_some(); let type_path = match form {
let type_path = match variant_ident { TupleForm::Tuple => construct,
Some(variant_ident) => quote!(#construct::#variant_ident), TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => {
None => construct, quote!(#construct::#variant_ident)
}
}; };
let expecting = match variant_ident { let expecting = match form {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), TupleForm::Tuple => format!("tuple struct {}", params.type_name()),
None => format!("tuple struct {}", params.type_name()), TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => {
format!("tuple variant {}::{}", params.type_name(), variant_ident)
}
}; };
let expecting = cattrs.expecting().unwrap_or(&expecting); let expecting = cattrs.expecting().unwrap_or(&expecting);
let nfields = fields.len(); let nfields = fields.len();
let visit_newtype_struct = if !is_enum && nfields == 1 { let visit_newtype_struct = match form {
Some(deserialize_newtype_struct(&type_path, params, &fields[0])) TupleForm::Tuple if nfields == 1 => {
} else { Some(deserialize_newtype_struct(&type_path, params, &fields[0]))
None }
_ => None,
}; };
let visit_seq = Stmts(deserialize_seq( let visit_seq = Stmts(deserialize_seq(
@@ -495,26 +509,35 @@ fn deserialize_tuple(
lifetime: _serde::__private::PhantomData, lifetime: _serde::__private::PhantomData,
} }
}; };
let dispatch = if let Some(deserializer) = deserializer { let dispatch = match form {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) TupleForm::Tuple if nfields == 1 => {
} else if is_enum { let type_name = cattrs.name().deserialize_name();
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) quote! {
} else if nfields == 1 { _serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)
let type_name = cattrs.name().deserialize_name(); }
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) }
} else { TupleForm::Tuple => {
let type_name = cattrs.name().deserialize_name(); let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) quote! {
_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)
}
}
TupleForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr)
},
TupleForm::Untagged(_, deserializer) => quote! {
_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr)
},
}; };
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); let visitor_var = if field_count == 0 {
let visitor_var = if all_skipped {
quote!(_) quote!(_)
} else { } else {
quote!(mut __seq) quote!(mut __seq)
}; };
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -550,13 +573,18 @@ fn deserialize_tuple_in_place(
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<TokenStream>, deserializer: Option<TokenStream>,
) -> Fragment { ) -> Fragment {
assert!(!cattrs.has_flatten());
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type; let this_type = &params.this_type;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params); split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
let is_enum = variant_ident.is_some(); let is_enum = variant_ident.is_some();
let expecting = match variant_ident { let expecting = match variant_ident {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
@@ -582,19 +610,18 @@ fn deserialize_tuple_in_place(
}; };
let dispatch = if let Some(deserializer) = deserializer { let dispatch = if let Some(deserializer) = deserializer {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr))
} else if is_enum { } else if is_enum {
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr))
} else if nfields == 1 { } else if nfields == 1 {
let type_name = cattrs.name().deserialize_name(); let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else { } else {
let type_name = cattrs.name().deserialize_name(); let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
}; };
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); let visitor_var = if field_count == 0 {
let visitor_var = if all_skipped {
quote!(_) quote!(_)
} else { } else {
quote!(mut __seq) quote!(mut __seq)
@@ -605,6 +632,7 @@ fn deserialize_tuple_in_place(
let place_life = place_lifetime(); let place_life = place_lifetime();
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause { struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics, place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -894,21 +922,24 @@ fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> To
} }
} }
enum Untagged { enum StructForm<'a> {
Yes, Struct,
No, /// Contains a variant name
ExternallyTagged(&'a syn::Ident),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
InternallyTagged(&'a syn::Ident, TokenStream),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
Untagged(&'a syn::Ident, TokenStream),
} }
fn deserialize_struct( fn deserialize_struct(
variant_ident: Option<&syn::Ident>,
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
deserializer: Option<TokenStream>, form: StructForm,
untagged: &Untagged,
) -> Fragment { ) -> Fragment {
let is_enum = variant_ident.is_some();
let this_type = &params.this_type; let this_type = &params.this_type;
let this_value = &params.this_value; let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
@@ -925,83 +956,74 @@ fn deserialize_struct(
quote!(#this_value) quote!(#this_value)
}; };
let type_path = match variant_ident { let type_path = match form {
Some(variant_ident) => quote!(#construct::#variant_ident), StructForm::Struct => construct,
None => construct, StructForm::ExternallyTagged(variant_ident)
| StructForm::InternallyTagged(variant_ident, _)
| StructForm::Untagged(variant_ident, _) => quote!(#construct::#variant_ident),
}; };
let expecting = match variant_ident { let expecting = match form {
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), StructForm::Struct => format!("struct {}", params.type_name()),
None => format!("struct {}", params.type_name()), StructForm::ExternallyTagged(variant_ident)
| StructForm::InternallyTagged(variant_ident, _)
| StructForm::Untagged(variant_ident, _) => {
format!("struct variant {}::{}", params.type_name(), variant_ident)
}
}; };
let expecting = cattrs.expecting().unwrap_or(&expecting); let expecting = cattrs.expecting().unwrap_or(&expecting);
let visit_seq = Stmts(deserialize_seq( let field_names_idents: Vec<_> = fields
&type_path, params, fields, true, cattrs, expecting, .iter()
.enumerate()
// Skip fields that shouldn't be deserialized or that were flattened,
// so they don't appear in the storage in their literal form
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(i, field)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let field_visitor = Stmts(deserialize_generated_identifier(
&field_names_idents,
cattrs,
false,
None,
)); ));
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs)
} else {
deserialize_struct_as_struct_visitor(&type_path, params, fields, cattrs)
};
let field_visitor = Stmts(field_visitor);
let fields_stmt = fields_stmt.map(Stmts);
let visit_map = Stmts(visit_map);
let visitor_expr = quote! {
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
}
};
let need_seed = deserializer.is_none();
let dispatch = if let Some(deserializer) = deserializer {
quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
}
} else if is_enum && cattrs.has_flatten() {
quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
}
} else if is_enum {
quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
}
} else if cattrs.has_flatten() {
quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
}
} else {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
quote!(_)
} else {
quote!(mut __seq)
};
// untagged struct variants do not get a visit_seq method. The same applies to // untagged struct variants do not get a visit_seq method. The same applies to
// structs that only have a map representation. // structs that only have a map representation.
let visit_seq = match *untagged { let visit_seq = match form {
Untagged::No if !cattrs.has_flatten() => Some(quote! { StructForm::Untagged(..) => None,
#[inline] _ if cattrs.has_flatten() => None,
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::__private::Result<Self::Value, __A::Error> _ => {
where let mut_seq = if field_names_idents.is_empty() {
__A: _serde::de::SeqAccess<#delife>, quote!(_)
{ } else {
#visit_seq quote!(mut __seq)
} };
}),
_ => None,
};
let visitor_seed = if need_seed && is_enum && cattrs.has_flatten() { let visit_seq = Stmts(deserialize_seq(
Some(quote! { &type_path, params, fields, true, cattrs, expecting,
));
Some(quote! {
#[inline]
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::__private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
})
}
};
let visit_map = Stmts(deserialize_map(&type_path, params, fields, cattrs));
let visitor_seed = match form {
StructForm::ExternallyTagged(..) if cattrs.has_flatten() => Some(quote! {
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics; type Value = #this_type #ty_generics;
@@ -1012,14 +1034,57 @@ fn deserialize_struct(
_serde::Deserializer::deserialize_map(__deserializer, self) _serde::Deserializer::deserialize_map(__deserializer, self)
} }
} }
}) }),
} else { _ => None,
};
let fields_stmt = if cattrs.has_flatten() {
None None
} else {
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
Some(quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
})
};
let visitor_expr = quote! {
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
}
};
let dispatch = match form {
StructForm::Struct if cattrs.has_flatten() => quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
},
StructForm::Struct => {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
}
StructForm::ExternallyTagged(_) if cattrs.has_flatten() => quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
},
StructForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
},
StructForm::InternallyTagged(_, deserializer) => quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
},
StructForm::Untagged(_, deserializer) => quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
},
}; };
quote_block! { quote_block! {
#field_visitor #field_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1132,6 +1197,7 @@ fn deserialize_struct_in_place(
Some(quote_block! { Some(quote_block! {
#field_visitor #field_visitor
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause { struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics, place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1165,6 +1231,22 @@ fn deserialize_enum(
params: &Parameters, params: &Parameters,
variants: &[Variant], variants: &[Variant],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment {
// The variants have already been checked (in ast.rs) that all untagged variants appear at the end
match variants.iter().position(|var| var.attrs.untagged()) {
Some(variant_idx) => {
let (tagged, untagged) = variants.split_at(variant_idx);
let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag))
}
None => deserialize_homogeneous_enum(params, variants, cattrs),
}
}
fn deserialize_homogeneous_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
match cattrs.tag() { match cattrs.tag() {
attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs),
@@ -1203,6 +1285,7 @@ fn prepare_enum_variant_enum(
let variants_stmt = { let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
quote! { quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
} }
}; };
@@ -1275,6 +1358,7 @@ fn deserialize_externally_tagged_enum(
quote_block! { quote_block! {
#variant_visitor #variant_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1329,9 +1413,7 @@ fn deserialize_internally_tagged_enum(
params, params,
variant, variant,
cattrs, cattrs,
quote! { quote!(__deserializer),
_serde::__private::de::ContentDeserializer::<__D::Error>::new(__tagged.content)
},
)); ));
quote! { quote! {
@@ -1347,11 +1429,12 @@ fn deserialize_internally_tagged_enum(
#variants_stmt #variants_stmt
let __tagged = try!(_serde::Deserializer::deserialize_any( let (__tag, __content) = try!(_serde::Deserializer::deserialize_any(
__deserializer, __deserializer,
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))); _serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting)));
let __deserializer = _serde::__private::de::ContentDeserializer::<__D::Error>::new(__content);
match __tagged.tag { match __tag {
#(#variant_arms)* #(#variant_arms)*
} }
} }
@@ -1522,6 +1605,7 @@ fn deserialize_adjacently_tagged_enum(
#variants_stmt #variants_stmt
#[doc(hidden)]
struct __Seed #de_impl_generics #where_clause { struct __Seed #de_impl_generics #where_clause {
field: __Field, field: __Field,
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1541,6 +1625,7 @@ fn deserialize_adjacently_tagged_enum(
} }
} }
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1643,6 +1728,7 @@ fn deserialize_adjacently_tagged_enum(
} }
} }
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content]; const FIELDS: &'static [&'static str] = &[#tag, #content];
_serde::Deserializer::deserialize_struct( _serde::Deserializer::deserialize_struct(
__deserializer, __deserializer,
@@ -1660,6 +1746,16 @@ fn deserialize_untagged_enum(
params: &Parameters, params: &Parameters,
variants: &[Variant], variants: &[Variant],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment {
let first_attempt = None;
deserialize_untagged_enum_after(params, variants, cattrs, first_attempt)
}
fn deserialize_untagged_enum_after(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
first_attempt: Option<Expr>,
) -> Fragment { ) -> Fragment {
let attempts = variants let attempts = variants
.iter() .iter()
@@ -1669,12 +1765,10 @@ fn deserialize_untagged_enum(
params, params,
variant, variant,
cattrs, cattrs,
quote!( quote!(__deserializer),
_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)
),
)) ))
}); });
let attempts = first_attempt.into_iter().chain(attempts);
// TODO this message could be better by saving the errors from the failed // TODO this message could be better by saving the errors from the failed
// attempts. The heuristic used by TOML was to count the number of fields // attempts. The heuristic used by TOML was to count the number of fields
// processed before an error, and use the error that happened after the // processed before an error, and use the error that happened after the
@@ -1689,6 +1783,7 @@ fn deserialize_untagged_enum(
quote_block! { quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer)); let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
#( #(
if let _serde::__private::Ok(__ok) = #attempts { if let _serde::__private::Ok(__ok) = #attempts {
@@ -1730,16 +1825,17 @@ fn deserialize_externally_tagged_variant(
&variant.fields[0], &variant.fields[0],
cattrs, cattrs,
), ),
Style::Tuple => { Style::Tuple => deserialize_tuple(
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
}
Style::Struct => deserialize_struct(
Some(variant_ident),
params, params,
&variant.fields, &variant.fields,
cattrs, cattrs,
None, TupleForm::ExternallyTagged(variant_ident),
&Untagged::No, ),
Style::Struct => deserialize_struct(
params,
&variant.fields,
cattrs,
StructForm::ExternallyTagged(variant_ident),
), ),
} }
} }
@@ -1779,12 +1875,10 @@ fn deserialize_internally_tagged_variant(
&deserializer, &deserializer,
), ),
Style::Struct => deserialize_struct( Style::Struct => deserialize_struct(
Some(variant_ident),
params, params,
&variant.fields, &variant.fields,
cattrs, cattrs,
Some(deserializer), StructForm::InternallyTagged(variant_ident, deserializer),
&Untagged::No,
), ),
Style::Tuple => unreachable!("checked in serde_derive_internals"), Style::Tuple => unreachable!("checked in serde_derive_internals"),
} }
@@ -1831,19 +1925,16 @@ fn deserialize_untagged_variant(
&deserializer, &deserializer,
), ),
Style::Tuple => deserialize_tuple( Style::Tuple => deserialize_tuple(
Some(variant_ident),
params, params,
&variant.fields, &variant.fields,
cattrs, cattrs,
Some(deserializer), TupleForm::Untagged(variant_ident, deserializer),
), ),
Style::Struct => deserialize_struct( Style::Struct => deserialize_struct(
Some(variant_ident),
params, params,
&variant.fields, &variant.fields,
cattrs, cattrs,
Some(deserializer), StructForm::Untagged(variant_ident, deserializer),
&Untagged::Yes,
), ),
} }
} }
@@ -1954,11 +2045,13 @@ fn deserialize_generated_identifier(
quote_block! { quote_block! {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field #lifetime { enum __Field #lifetime {
#(#field_idents,)* #(#field_idents,)*
#ignore_variant #ignore_variant
} }
#[doc(hidden)]
struct __FieldVisitor; struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
@@ -2046,11 +2139,13 @@ fn deserialize_custom_identifier(
None None
} else if is_variant { } else if is_variant {
let variants = quote! { let variants = quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
}; };
Some(variants) Some(variants)
} else { } else {
let fields = quote! { let fields = quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#names),* ]; const FIELDS: &'static [&'static str] = &[ #(#names),* ];
}; };
Some(fields) Some(fields)
@@ -2072,6 +2167,7 @@ fn deserialize_custom_identifier(
quote_block! { quote_block! {
#names_const #names_const
#[doc(hidden)]
struct __FieldVisitor #de_impl_generics #where_clause { struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -2379,70 +2475,6 @@ fn deserialize_identifier(
} }
} }
fn deserialize_struct_as_struct_visitor(
struct_path: &TokenStream,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Option<Fragment>, Fragment) {
assert!(!cattrs.has_flatten());
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing())
.map(|(i, field)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let fields_stmt = {
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
};
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
(field_visitor, Some(fields_stmt), visit_map)
}
fn deserialize_struct_as_map_visitor(
struct_path: &TokenStream,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Option<Fragment>, Fragment) {
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(i, field)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
(field_visitor, None, visit_map)
}
fn deserialize_map( fn deserialize_map(
struct_path: &TokenStream, struct_path: &TokenStream,
params: &Parameters, params: &Parameters,
@@ -2684,6 +2716,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
let fields_stmt = { let fields_stmt = {
let field_names = field_names_idents.iter().map(|(name, _, _)| name); let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! { quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
} }
}; };
@@ -2864,6 +2897,7 @@ fn wrap_deserialize_with(
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
let wrapper = quote! { let wrapper = quote! {
#[doc(hidden)]
struct __DeserializeWith #de_impl_generics #where_clause { struct __DeserializeWith #de_impl_generics #where_clause {
value: #value_ty, value: #value_ty,
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -3068,23 +3102,31 @@ struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
struct InPlaceTypeGenerics<'a>(&'a Parameters); struct InPlaceTypeGenerics<'a>(&'a Parameters);
fn de_type_generics_to_tokens(
mut generics: syn::Generics,
borrowed: &BorrowedLifetimes,
tokens: &mut TokenStream,
) {
if borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
// Prepend 'de lifetime to list of generics
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
impl<'a> ToTokens for DeTypeGenerics<'a> { impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone(); de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens);
if self.0.borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
} }
} }
@@ -3097,20 +3139,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
.chain(generics.params) .chain(generics.params)
.collect(); .collect();
if self.0.borrowed.de_lifetime_param().is_some() { de_type_generics_to_tokens(generics, &self.0.borrowed, tokens);
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
} }
} }
+3 -19
View File
@@ -1,23 +1,11 @@
use proc_macro2::{Ident, TokenStream}; use proc_macro2::TokenStream;
use quote::format_ident;
use syn; use syn;
use try; use try;
pub fn wrap_in_const( pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
let try_replacement = try::replacement(); let try_replacement = try::replacement();
let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};
let use_serde = match serde_path { let use_serde = match serde_path {
Some(path) => quote! { Some(path) => quote! {
use #path as _serde; use #path as _serde;
@@ -31,14 +19,10 @@ pub fn wrap_in_const(
quote! { quote! {
#[doc(hidden)] #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = { const _: () = {
#use_serde #use_serde
#try_replacement #try_replacement
#code #code
}; };
} }
} }
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
+15 -2
View File
@@ -140,7 +140,7 @@ fn enum_from_ast<'a>(
variants: &'a Punctuated<syn::Variant, Token![,]>, variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default, container_default: &attr::Default,
) -> Vec<Variant<'a>> { ) -> Vec<Variant<'a>> {
variants let variants: Vec<Variant> = variants
.iter() .iter()
.map(|variant| { .map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant); let attrs = attr::Variant::from_ast(cx, variant);
@@ -154,7 +154,20 @@ fn enum_from_ast<'a>(
original: variant, original: variant,
} }
}) })
.collect() .collect();
let index_of_last_tagged_variant = variants
.iter()
.rposition(|variant| !variant.attrs.untagged());
if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant {
for variant in &variants[..index_of_last_tagged_variant] {
if variant.attrs.untagged() {
cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");
}
}
}
variants
} }
fn struct_from_ast<'a>( fn struct_from_ast<'a>(
+9
View File
@@ -740,6 +740,7 @@ pub struct Variant {
serialize_with: Option<syn::ExprPath>, serialize_with: Option<syn::ExprPath>,
deserialize_with: Option<syn::ExprPath>, deserialize_with: Option<syn::ExprPath>,
borrow: Option<BorrowAttribute>, borrow: Option<BorrowAttribute>,
untagged: bool,
} }
struct BorrowAttribute { struct BorrowAttribute {
@@ -762,6 +763,7 @@ impl Variant {
let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); let mut serialize_with = Attr::none(cx, SERIALIZE_WITH);
let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH);
let mut borrow = Attr::none(cx, BORROW); let mut borrow = Attr::none(cx, BORROW);
let mut untagged = BoolAttr::none(cx, UNTAGGED);
for attr in &variant.attrs { for attr in &variant.attrs {
if attr.path() != SERDE { if attr.path() != SERDE {
@@ -879,6 +881,8 @@ impl Variant {
cx.error_spanned_by(variant, msg); cx.error_spanned_by(variant, msg);
} }
} }
} else if meta.path == UNTAGGED {
untagged.set_true(&meta.path);
} else { } else {
let path = meta.path.to_token_stream().to_string().replace(' ', ""); let path = meta.path.to_token_stream().to_string().replace(' ', "");
return Err( return Err(
@@ -905,6 +909,7 @@ impl Variant {
serialize_with: serialize_with.get(), serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(), deserialize_with: deserialize_with.get(),
borrow: borrow.get(), borrow: borrow.get(),
untagged: untagged.get(),
} }
} }
@@ -956,6 +961,10 @@ impl Variant {
pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { pub fn deserialize_with(&self) -> Option<&syn::ExprPath> {
self.deserialize_with.as_ref() self.deserialize_with.as_ref()
} }
pub fn untagged(&self) -> bool {
self.untagged
}
} }
/// Represents field attribute information /// Represents field attribute information
+3 -7
View File
@@ -110,9 +110,7 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
fn check_identifier(cx: &Ctxt, cont: &Container) { fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data { let variants = match &cont.data {
Data::Enum(variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => return,
return;
}
}; };
for (i, variant) in variants.iter().enumerate() { for (i, variant) in variants.iter().enumerate() {
@@ -194,12 +192,10 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data { let variants = match &cont.data {
Data::Enum(variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => return,
return;
}
}; };
for variant in variants.iter() { for variant in variants {
if variant.attrs.serialize_with().is_some() { if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() { if variant.attrs.skip_serializing() {
cx.error_spanned_by( cx.error_spanned_by(
+12 -5
View File
@@ -44,12 +44,19 @@ impl Ctxt {
} }
/// Consume this object, producing a formatted error string if there are errors. /// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> Result<(), Vec<syn::Error>> { pub fn check(self) -> syn::Result<()> {
let errors = self.errors.borrow_mut().take().unwrap(); let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
match errors.len() {
0 => Ok(()), let mut combined = match errors.next() {
_ => Err(errors), Some(first) => first,
None => return Ok(()),
};
for rest in errors {
combined.combine(rest);
} }
Err(combined)
} }
} }
+5 -10
View File
@@ -1,7 +1,7 @@
//! This crate provides Serde's two derive macros. //! This crate provides Serde's two derive macros.
//! //!
//! ```edition2018 //! ```edition2021
//! # use serde_derive::{Serialize, Deserialize}; //! # use serde_derive::{Deserialize, Serialize};
//! # //! #
//! #[derive(Serialize, Deserialize)] //! #[derive(Serialize, Deserialize)]
//! # struct S; //! # struct S;
@@ -13,7 +13,7 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.159")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.167")]
#![allow(unknown_lints, bare_trait_objects)] #![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
@@ -92,7 +92,7 @@ mod try;
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput); let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input) ser::expand_derive_serialize(&mut input)
.unwrap_or_else(to_compile_errors) .unwrap_or_else(syn::Error::into_compile_error)
.into() .into()
} }
@@ -100,11 +100,6 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
pub fn derive_deserialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput); let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input) de::expand_derive_deserialize(&mut input)
.unwrap_or_else(to_compile_errors) .unwrap_or_else(syn::Error::into_compile_error)
.into() .into()
} }
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
+7 -22
View File
@@ -97,29 +97,14 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>(); let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(not(no_ptr_addr_of))] quote! {
{ match _serde::__private::None::<&#type_ident #ty_generics> {
quote! { _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
match _serde::__private::None::<&#type_ident #ty_generics> { #(
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => { let _ = _serde::__private::ptr::addr_of!(__v.#members);
#( )*
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
#[cfg(no_ptr_addr_of)]
{
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
} }
_ => {}
} }
} }
} }
+11 -10
View File
@@ -10,9 +10,7 @@ use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend; use pretend;
use this; use this;
pub fn expand_derive_serialize( pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input); replace_receiver(input);
let ctxt = Ctxt::new(); let ctxt = Ctxt::new();
@@ -59,8 +57,6 @@ pub fn expand_derive_serialize(
Ok(dummy::wrap_in_const( Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(), cont.attrs.custom_serde_path(),
"SERIALIZE",
ident,
impl_block, impl_block,
)) ))
} }
@@ -477,17 +473,19 @@ fn serialize_variant(
} }
}; };
let body = Match(match cattrs.tag() { let body = Match(match (cattrs.tag(), variant.attrs.untagged()) {
attr::TagType::External => { (attr::TagType::External, false) => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs) serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
} }
attr::TagType::Internal { tag } => { (attr::TagType::Internal { tag }, false) => {
serialize_internally_tagged_variant(params, variant, cattrs, tag) serialize_internally_tagged_variant(params, variant, cattrs, tag)
} }
attr::TagType::Adjacent { tag, content } => { (attr::TagType::Adjacent { tag, content }, false) => {
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content) serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
} }
attr::TagType::None => serialize_untagged_variant(params, variant, cattrs), (attr::TagType::None, _) | (_, true) => {
serialize_untagged_variant(params, variant, cattrs)
}
}); });
quote! { quote! {
@@ -719,6 +717,7 @@ fn serialize_adjacently_tagged_variant(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! { quote_block! {
#[doc(hidden)]
struct __AdjacentlyTagged #wrapper_generics #where_clause { struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*), data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -982,6 +981,7 @@ fn serialize_struct_variant_with_flatten(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! { quote_block! {
#[doc(hidden)]
struct __EnumFlatten #wrapper_generics #where_clause { struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*), data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1212,6 +1212,7 @@ fn wrap_serialize_with(
}); });
quote!({ quote!({
#[doc(hidden)]
struct __SerializeWith #wrapper_impl_generics #where_clause { struct __SerializeWith #wrapper_impl_generics #where_clause {
values: (#(&'__a #field_tys, )*), values: (#(&'__a #field_tys, )*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.27.0" # remember to update html_root_url version = "0.28.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable." description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals" documentation = "https://docs.rs/serde_derive_internals"
@@ -17,7 +17,7 @@ path = "lib.rs"
[dependencies] [dependencies]
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = { version = "2.0", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } syn = { version = "2.0.21", default-features = false, features = ["clone-impls", "derive", "parsing", "printing"] }
[package.metadata.docs.rs] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]
+1 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.27.0")] #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
#![allow(unknown_lints, bare_trait_objects)] #![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.159" # remember to update html_root_url version = "1.0.167" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["development-tools::testing"] categories = ["development-tools::testing"]
@@ -18,7 +18,7 @@ rust-version = "1.19"
serde = { version = "1.0.60", path = "../serde" } serde = { version = "1.0.60", path = "../serde" }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde", features = ["rc"] }
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
[lib] [lib]
+54 -40
View File
@@ -8,8 +8,8 @@ use std::fmt::Debug;
/// Runs both `assert_ser_tokens` and `assert_de_tokens`. /// Runs both `assert_ser_tokens` and `assert_de_tokens`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -19,14 +19,17 @@ use std::fmt::Debug;
/// } /// }
/// ///
/// let s = S { a: 0, b: 0 }; /// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[ /// assert_tokens(
/// Token::Struct { name: "S", len: 2 }, /// &s,
/// Token::Str("a"), /// &[
/// Token::U8(0), /// Token::Struct { name: "S", len: 2 },
/// Token::Str("b"), /// Token::Str("a"),
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::Str("b"),
/// ]); /// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ``` /// ```
#[cfg_attr(not(no_track_caller), track_caller)] #[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token]) pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
@@ -39,8 +42,8 @@ where
/// Asserts that `value` serializes to the given `tokens`. /// Asserts that `value` serializes to the given `tokens`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_ser_tokens, Token}; /// # use serde_test::{assert_ser_tokens, Token};
/// # /// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -50,14 +53,17 @@ where
/// } /// }
/// ///
/// let s = S { a: 0, b: 0 }; /// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(&s, &[ /// assert_ser_tokens(
/// Token::Struct { name: "S", len: 2 }, /// &s,
/// Token::Str("a"), /// &[
/// Token::U8(0), /// Token::Struct { name: "S", len: 2 },
/// Token::Str("b"), /// Token::Str("a"),
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::Str("b"),
/// ]); /// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ``` /// ```
#[cfg_attr(not(no_track_caller), track_caller)] #[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token]) pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token])
@@ -78,23 +84,24 @@ where
/// Asserts that `value` serializes to the given `tokens`, and then yields /// Asserts that `value` serializes to the given `tokens`, and then yields
/// `error`. /// `error`.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde_derive::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
/// use std::sync::{Arc, Mutex}; /// use std::sync::{Arc, Mutex};
/// use std::thread; /// use std::thread;
/// ///
/// use serde::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)] /// #[derive(Serialize)]
/// struct Example { /// struct Example {
/// lock: Arc<Mutex<u32>>, /// lock: Arc<Mutex<u32>>,
/// } /// }
/// ///
/// fn main() { /// fn main() {
/// let example = Example { lock: Arc::new(Mutex::new(0)) }; /// let example = Example {
/// lock: Arc::new(Mutex::new(0)),
/// };
/// let lock = example.lock.clone(); /// let lock = example.lock.clone();
/// ///
/// let _ = thread::spawn(move || { /// let thread = thread::spawn(move || {
/// // This thread will acquire the mutex first, unwrapping the result /// // This thread will acquire the mutex first, unwrapping the result
/// // of `lock` because the lock has not been poisoned. /// // of `lock` because the lock has not been poisoned.
/// let _guard = lock.lock().unwrap(); /// let _guard = lock.lock().unwrap();
@@ -102,10 +109,14 @@ where
/// // This panic while holding the lock (`_guard` is in scope) will /// // This panic while holding the lock (`_guard` is in scope) will
/// // poison the mutex. /// // poison the mutex.
/// panic!() /// panic!()
/// }).join(); /// });
/// thread.join();
/// ///
/// let expected = &[ /// let expected = &[
/// Token::Struct { name: "Example", len: 1 }, /// Token::Struct {
/// name: "Example",
/// len: 1,
/// },
/// Token::Str("lock"), /// Token::Str("lock"),
/// ]; /// ];
/// let error = "lock poison error while serializing"; /// let error = "lock poison error while serializing";
@@ -130,8 +141,8 @@ where
/// Asserts that the given `tokens` deserialize into `value`. /// Asserts that the given `tokens` deserialize into `value`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens, Token}; /// # use serde_test::{assert_de_tokens, Token};
/// # /// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -141,14 +152,17 @@ where
/// } /// }
/// ///
/// let s = S { a: 0, b: 0 }; /// let s = S { a: 0, b: 0 };
/// assert_de_tokens(&s, &[ /// assert_de_tokens(
/// Token::Struct { name: "S", len: 2 }, /// &s,
/// Token::Str("a"), /// &[
/// Token::U8(0), /// Token::Struct { name: "S", len: 2 },
/// Token::Str("b"), /// Token::Str("a"),
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::Str("b"),
/// ]); /// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ``` /// ```
#[cfg_attr(not(no_track_caller), track_caller)] #[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
@@ -184,8 +198,8 @@ where
/// Asserts that the given `tokens` yield `error` when deserializing. /// Asserts that the given `tokens` yield `error` when deserializing.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens_error, Token}; /// # use serde_test::{assert_de_tokens_error, Token};
/// # /// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct Compact<T: ?Sized>(T);
/// Trait to determine whether a value is represented in human-readable or /// Trait to determine whether a value is represented in human-readable or
/// compact form. /// compact form.
/// ///
/// ```edition2018 /// ```edition2021
/// use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{assert_tokens, Configure, Token}; /// use serde_test::{assert_tokens, Configure, Token};
/// ///
+83 -95
View File
@@ -12,32 +12,29 @@ pub struct Deserializer<'de> {
tokens: &'de [Token], tokens: &'de [Token],
} }
macro_rules! assert_next_token { fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
($de:expr, $expected:expr) => { match de.next_token_opt() {
match $de.next_token_opt() { Some(token) if token == expected => Ok(()),
Some(token) if token == $expected => {} Some(other) => Err(de::Error::custom(format!(
Some(other) => panic!( "expected Token::{} but deserialization wants Token::{}",
"expected Token::{} but deserialization wants Token::{}", other, expected,
other, $expected ))),
), None => Err(de::Error::custom(format!(
None => panic!( "end of tokens but deserialization wants Token::{}",
"end of tokens but deserialization wants Token::{}", expected,
$expected ))),
), }
}
};
} }
macro_rules! unexpected { fn unexpected(token: Token) -> Error {
($token:expr) => { de::Error::custom(format!(
panic!("deserialization did not expect this token: {}", $token) "deserialization did not expect this token: {}",
}; token,
))
} }
macro_rules! end_of_tokens { fn end_of_tokens() -> Error {
() => { de::Error::custom("ran out of tokens to deserialize")
panic!("ran out of tokens to deserialize")
};
} }
impl<'de> Deserializer<'de> { impl<'de> Deserializer<'de> {
@@ -49,11 +46,8 @@ impl<'de> Deserializer<'de> {
self.tokens.first().cloned() self.tokens.first().cloned()
} }
fn peek_token(&self) -> Token { fn peek_token(&self) -> Result<Token, Error> {
match self.peek_token_opt() { self.peek_token_opt().ok_or_else(end_of_tokens)
Some(token) => token,
None => end_of_tokens!(),
}
} }
pub fn next_token_opt(&mut self) -> Option<Token> { pub fn next_token_opt(&mut self) -> Option<Token> {
@@ -66,14 +60,10 @@ impl<'de> Deserializer<'de> {
} }
} }
fn next_token(&mut self) -> Token { fn next_token(&mut self) -> Result<Token, Error> {
match self.tokens.split_first() { let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
Some((&first, rest)) => { self.tokens = rest;
self.tokens = rest; Ok(first)
first
}
None => end_of_tokens!(),
}
} }
pub fn remaining(&self) -> usize { pub fn remaining(&self) -> usize {
@@ -94,7 +84,7 @@ impl<'de> Deserializer<'de> {
len: len, len: len,
end: end, end: end,
})?; })?;
assert_next_token!(self, end); assert_next_token(self, end)?;
Ok(value) Ok(value)
} }
@@ -112,7 +102,7 @@ impl<'de> Deserializer<'de> {
len: len, len: len,
end: end, end: end,
})?; })?;
assert_next_token!(self, end); assert_next_token(self, end)?;
Ok(value) Ok(value)
} }
} }
@@ -129,7 +119,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let token = self.next_token(); let token = self.next_token()?;
match token { match token {
Token::Bool(v) => visitor.visit_bool(v), Token::Bool(v) => visitor.visit_bool(v),
Token::I8(v) => visitor.visit_i8(v), Token::I8(v) => visitor.visit_i8(v),
@@ -161,50 +151,50 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor), Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor), Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => { Token::Enum { .. } => {
let variant = self.next_token(); let variant = self.next_token()?;
let next = self.peek_token(); let next = self.peek_token()?;
match (variant, next) { match (variant, next) {
(Token::Str(variant), Token::Unit) => { (Token::Str(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_str(variant) visitor.visit_str(variant)
} }
(Token::BorrowedStr(variant), Token::Unit) => { (Token::BorrowedStr(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_borrowed_str(variant) visitor.visit_borrowed_str(variant)
} }
(Token::String(variant), Token::Unit) => { (Token::String(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_string(variant.to_string()) visitor.visit_string(variant.to_string())
} }
(Token::Bytes(variant), Token::Unit) => { (Token::Bytes(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_bytes(variant) visitor.visit_bytes(variant)
} }
(Token::BorrowedBytes(variant), Token::Unit) => { (Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_borrowed_bytes(variant) visitor.visit_borrowed_bytes(variant)
} }
(Token::ByteBuf(variant), Token::Unit) => { (Token::ByteBuf(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_byte_buf(variant.to_vec()) visitor.visit_byte_buf(variant.to_vec())
} }
(Token::U8(variant), Token::Unit) => { (Token::U8(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u8(variant) visitor.visit_u8(variant)
} }
(Token::U16(variant), Token::Unit) => { (Token::U16(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u16(variant) visitor.visit_u16(variant)
} }
(Token::U32(variant), Token::Unit) => { (Token::U32(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u32(variant) visitor.visit_u32(variant)
} }
(Token::U64(variant), Token::Unit) => { (Token::U64(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u64(variant) visitor.visit_u64(variant)
} }
(variant, Token::Unit) => unexpected!(variant), (variant, Token::Unit) => Err(unexpected(variant)),
(variant, _) => { (variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any)) visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
} }
@@ -232,9 +222,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
| Token::MapEnd | Token::MapEnd
| Token::StructEnd | Token::StructEnd
| Token::TupleVariantEnd | Token::TupleVariantEnd
| Token::StructVariantEnd => { | Token::StructVariantEnd => Err(unexpected(token)),
unexpected!(token);
}
} }
} }
@@ -242,13 +230,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit | Token::None => { Token::Unit | Token::None => {
self.next_token(); self.next_token()?;
visitor.visit_none() visitor.visit_none()
} }
Token::Some => { Token::Some => {
self.next_token(); self.next_token()?;
visitor.visit_some(self) visitor.visit_some(self)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -264,9 +252,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Enum { name: n } if name == n => { Token::Enum { name: n } if name == n => {
self.next_token(); self.next_token()?;
visitor.visit_enum(DeserializerEnumVisitor { de: self }) visitor.visit_enum(DeserializerEnumVisitor { de: self })
} }
@@ -286,9 +274,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::UnitStruct { .. } => { Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name }); assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit() visitor.visit_unit()
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -303,9 +291,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::NewtypeStruct { .. } => { Token::NewtypeStruct { .. } => {
assert_next_token!(self, Token::NewtypeStruct { name: name }); assert_next_token(self, Token::NewtypeStruct { name: name })?;
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -316,21 +304,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit | Token::UnitStruct { .. } => { Token::Unit | Token::UnitStruct { .. } => {
self.next_token(); self.next_token()?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::Seq { .. } => { Token::Seq { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor) self.visit_seq(Some(len), Token::SeqEnd, visitor)
} }
Token::Tuple { .. } => { Token::Tuple { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor) self.visit_seq(Some(len), Token::TupleEnd, visitor)
} }
Token::TupleStruct { .. } => { Token::TupleStruct { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor) self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -346,25 +334,25 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit => { Token::Unit => {
self.next_token(); self.next_token()?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::UnitStruct { .. } => { Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name }); assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::Seq { .. } => { Token::Seq { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor) self.visit_seq(Some(len), Token::SeqEnd, visitor)
} }
Token::Tuple { .. } => { Token::Tuple { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor) self.visit_seq(Some(len), Token::TupleEnd, visitor)
} }
Token::TupleStruct { len: n, .. } => { Token::TupleStruct { len: n, .. } => {
assert_next_token!(self, Token::TupleStruct { name: name, len: n }); assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor) self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -380,13 +368,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Struct { len: n, .. } => { Token::Struct { len: n, .. } => {
assert_next_token!(self, Token::Struct { name: name, len: n }); assert_next_token(self, Token::Struct { name: name, len: n })?;
self.visit_map(Some(fields.len()), Token::StructEnd, visitor) self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
} }
Token::Map { .. } => { Token::Map { .. } => {
self.next_token(); self.next_token()?;
self.visit_map(Some(fields.len()), Token::MapEnd, visitor) self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -476,7 +464,7 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: DeserializeSeed<'de>, V: DeserializeSeed<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::UnitVariant { variant: v, .. } Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. } | Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. } | Token::TupleVariant { variant: v, .. }
@@ -497,9 +485,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error; type Error = Error;
fn unit_variant(self) -> Result<(), Error> { fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token() { match self.de.peek_token()? {
Token::UnitVariant { .. } => { Token::UnitVariant { .. } => {
self.de.next_token(); self.de.next_token()?;
Ok(()) Ok(())
} }
_ => Deserialize::deserialize(self.de), _ => Deserialize::deserialize(self.de),
@@ -510,9 +498,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::NewtypeVariant { .. } => { Token::NewtypeVariant { .. } => {
self.de.next_token(); self.de.next_token()?;
seed.deserialize(self.de) seed.deserialize(self.de)
} }
_ => seed.deserialize(self.de), _ => seed.deserialize(self.de),
@@ -523,26 +511,26 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::TupleVariant { len: enum_len, .. } => { Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if len == enum_len { if len == enum_len {
self.de self.de
.visit_seq(Some(len), Token::TupleVariantEnd, visitor) .visit_seq(Some(len), Token::TupleVariantEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
Token::Seq { Token::Seq {
len: Some(enum_len), len: Some(enum_len),
} => { } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if len == enum_len { if len == enum_len {
self.de.visit_seq(Some(len), Token::SeqEnd, visitor) self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
_ => de::Deserializer::deserialize_any(self.de, visitor), _ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -557,27 +545,27 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::StructVariant { len: enum_len, .. } => { Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if fields.len() == enum_len { if fields.len() == enum_len {
self.de self.de
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor) .visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
Token::Map { Token::Map {
len: Some(enum_len), len: Some(enum_len),
} => { } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if fields.len() == enum_len { if fields.len() == enum_len {
self.de self.de
.visit_map(Some(fields.len()), Token::MapEnd, visitor) .visit_map(Some(fields.len()), Token::MapEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
_ => de::Deserializer::deserialize_any(self.de, visitor), _ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -622,7 +610,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
.deserialize(BytesDeserializer { value: variant }) .deserialize(BytesDeserializer { value: variant })
.map(Some), .map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other), Some(other) => Err(unexpected(other)),
None => Ok(None), None => Ok(None),
} }
} }
@@ -641,7 +629,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
}; };
seed.deserialize(SeqAccessDeserializer::new(visitor))? seed.deserialize(SeqAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::TupleVariantEnd); assert_next_token(self.de, Token::TupleVariantEnd)?;
Ok(value) Ok(value)
} }
EnumFormat::Map => { EnumFormat::Map => {
@@ -653,7 +641,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
}; };
seed.deserialize(MapAccessDeserializer::new(visitor))? seed.deserialize(MapAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::StructVariantEnd); assert_next_token(self.de, Token::StructVariantEnd)?;
Ok(value) Ok(value)
} }
EnumFormat::Any => seed.deserialize(&mut *self.de), EnumFormat::Any => seed.deserialize(&mut *self.de),
+23 -23
View File
@@ -20,11 +20,11 @@
//! //!
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map //! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
//! //!
//! ```edition2018 //! ```edition2021
//! # const IGNORE: &str = stringify! { //! # const IGNORE: &str = stringify! {
//! use linked_hash_map::LinkedHashMap; //! use linked_hash_map::LinkedHashMap;
//! # }; //! # };
//! use serde_test::{Token, assert_tokens}; //! use serde_test::{assert_tokens, Token};
//! //!
//! # use std::fmt; //! # use std::fmt;
//! # use std::marker::PhantomData; //! # use std::marker::PhantomData;
@@ -106,10 +106,13 @@
//! fn test_ser_de_empty() { //! fn test_ser_de_empty() {
//! let map = LinkedHashMap::<char, u32>::new(); //! let map = LinkedHashMap::<char, u32>::new();
//! //!
//! assert_tokens(&map, &[ //! assert_tokens(
//! Token::Map { len: Some(0) }, //! &map,
//! Token::MapEnd, //! &[
//! ]); //! Token::Map { len: Some(0) },
//! Token::MapEnd,
//! ],
//! );
//! } //! }
//! //!
//! #[test] //! #[test]
@@ -120,18 +123,19 @@
//! map.insert('a', 10); //! map.insert('a', 10);
//! map.insert('c', 30); //! map.insert('c', 30);
//! //!
//! assert_tokens(&map, &[ //! assert_tokens(
//! Token::Map { len: Some(3) }, //! &map,
//! Token::Char('b'), //! &[
//! Token::I32(20), //! Token::Map { len: Some(3) },
//! //! Token::Char('b'),
//! Token::Char('a'), //! Token::I32(20),
//! Token::I32(10), //! Token::Char('a'),
//! //! Token::I32(10),
//! Token::Char('c'), //! Token::Char('c'),
//! Token::I32(30), //! Token::I32(30),
//! Token::MapEnd, //! Token::MapEnd,
//! ]); //! ],
//! );
//! } //! }
//! # //! #
//! # fn main() { //! # fn main() {
@@ -140,7 +144,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.159")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.167")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints // Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
@@ -182,7 +186,3 @@ pub use assert::{
pub use token::Token; pub use token::Token;
pub use configure::{Compact, Configure, Readable}; pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
+6 -8
View File
@@ -63,14 +63,12 @@ macro_rules! assert_next_token {
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => { ($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() { match $ser.next_token() {
Some($pat) if $guard => {} Some($pat) if $guard => {}
Some(expected) => { Some(expected) => return Err(ser::Error::custom(
panic!("expected Token::{} but serialized as {}", format!("expected Token::{} but serialized as {}", expected, $actual)
expected, $actual); )),
} None => return Err(ser::Error::custom(
None => { format!("expected end of tokens, but {} was serialized", $actual)
panic!("expected end of tokens, but {} was serialized", )),
$actual);
}
} }
}; };
} }
+167 -125
View File
@@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Display};
pub enum Token { pub enum Token {
/// A serialized `bool`. /// A serialized `bool`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&true, &[Token::Bool(true)]); /// assert_tokens(&true, &[Token::Bool(true)]);
@@ -13,7 +13,7 @@ pub enum Token {
/// A serialized `i8`. /// A serialized `i8`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0i8, &[Token::I8(0)]); /// assert_tokens(&0i8, &[Token::I8(0)]);
@@ -22,7 +22,7 @@ pub enum Token {
/// A serialized `i16`. /// A serialized `i16`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0i16, &[Token::I16(0)]); /// assert_tokens(&0i16, &[Token::I16(0)]);
@@ -31,7 +31,7 @@ pub enum Token {
/// A serialized `i32`. /// A serialized `i32`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0i32, &[Token::I32(0)]); /// assert_tokens(&0i32, &[Token::I32(0)]);
@@ -40,7 +40,7 @@ pub enum Token {
/// A serialized `i64`. /// A serialized `i64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0i64, &[Token::I64(0)]); /// assert_tokens(&0i64, &[Token::I64(0)]);
@@ -49,7 +49,7 @@ pub enum Token {
/// A serialized `u8`. /// A serialized `u8`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0u8, &[Token::U8(0)]); /// assert_tokens(&0u8, &[Token::U8(0)]);
@@ -58,7 +58,7 @@ pub enum Token {
/// A serialized `u16`. /// A serialized `u16`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0u16, &[Token::U16(0)]); /// assert_tokens(&0u16, &[Token::U16(0)]);
@@ -67,7 +67,7 @@ pub enum Token {
/// A serialized `u32`. /// A serialized `u32`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0u32, &[Token::U32(0)]); /// assert_tokens(&0u32, &[Token::U32(0)]);
@@ -76,7 +76,7 @@ pub enum Token {
/// A serialized `u64`. /// A serialized `u64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0u64, &[Token::U64(0)]); /// assert_tokens(&0u64, &[Token::U64(0)]);
@@ -85,7 +85,7 @@ pub enum Token {
/// A serialized `f32`. /// A serialized `f32`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0f32, &[Token::F32(0.0)]); /// assert_tokens(&0f32, &[Token::F32(0.0)]);
@@ -94,7 +94,7 @@ pub enum Token {
/// A serialized `f64`. /// A serialized `f64`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&0f64, &[Token::F64(0.0)]); /// assert_tokens(&0f64, &[Token::F64(0.0)]);
@@ -103,7 +103,7 @@ pub enum Token {
/// A serialized `char`. /// A serialized `char`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&'\n', &[Token::Char('\n')]); /// assert_tokens(&'\n', &[Token::Char('\n')]);
@@ -112,7 +112,7 @@ pub enum Token {
/// A serialized `str`. /// A serialized `str`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let s = String::from("transient"); /// let s = String::from("transient");
@@ -122,7 +122,7 @@ pub enum Token {
/// A borrowed `str`. /// A borrowed `str`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let s: &str = "borrowed"; /// let s: &str = "borrowed";
@@ -132,7 +132,7 @@ pub enum Token {
/// A serialized `String`. /// A serialized `String`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let s = String::from("owned"); /// let s = String::from("owned");
@@ -151,7 +151,7 @@ pub enum Token {
/// A serialized `Option<T>` containing none. /// A serialized `Option<T>` containing none.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let opt = None::<char>; /// let opt = None::<char>;
@@ -163,20 +163,17 @@ pub enum Token {
/// ///
/// The tokens of the value follow after this header. /// The tokens of the value follow after this header.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let opt = Some('c'); /// let opt = Some('c');
/// assert_tokens(&opt, &[ /// assert_tokens(&opt, &[Token::Some, Token::Char('c')]);
/// Token::Some,
/// Token::Char('c'),
/// ]);
/// ``` /// ```
Some, Some,
/// A serialized `()`. /// A serialized `()`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// assert_tokens(&(), &[Token::Unit]); /// assert_tokens(&(), &[Token::Unit]);
@@ -185,8 +182,8 @@ pub enum Token {
/// A serialized unit struct of the given name. /// A serialized unit struct of the given name.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -200,8 +197,8 @@ pub enum Token {
/// A unit variant of an enum. /// A unit variant of an enum.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -211,7 +208,13 @@ pub enum Token {
/// } /// }
/// ///
/// let a = E::A; /// let a = E::A;
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]); /// assert_tokens(
/// &a,
/// &[Token::UnitVariant {
/// name: "E",
/// variant: "A",
/// }],
/// );
/// # } /// # }
/// ``` /// ```
UnitVariant { UnitVariant {
@@ -223,8 +226,8 @@ pub enum Token {
/// ///
/// After this header is the value contained in the newtype struct. /// After this header is the value contained in the newtype struct.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -232,10 +235,10 @@ pub enum Token {
/// struct N(String); /// struct N(String);
/// ///
/// let n = N("newtype".to_owned()); /// let n = N("newtype".to_owned());
/// assert_tokens(&n, &[ /// assert_tokens(
/// Token::NewtypeStruct { name: "N" }, /// &n,
/// Token::String("newtype"), /// &[Token::NewtypeStruct { name: "N" }, Token::String("newtype")],
/// ]); /// );
/// # } /// # }
/// ``` /// ```
NewtypeStruct { name: &'static str }, NewtypeStruct { name: &'static str },
@@ -244,8 +247,8 @@ pub enum Token {
/// ///
/// After this header is the value contained in the newtype variant. /// After this header is the value contained in the newtype variant.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -255,10 +258,16 @@ pub enum Token {
/// } /// }
/// ///
/// let b = E::B(0); /// let b = E::B(0);
/// assert_tokens(&b, &[ /// assert_tokens(
/// Token::NewtypeVariant { name: "E", variant: "B" }, /// &b,
/// Token::U8(0), /// &[
/// ]); /// Token::NewtypeVariant {
/// name: "E",
/// variant: "B",
/// },
/// Token::U8(0),
/// ],
/// );
/// # } /// # }
/// ``` /// ```
NewtypeVariant { NewtypeVariant {
@@ -271,17 +280,20 @@ pub enum Token {
/// After this header are the elements of the sequence, followed by /// After this header are the elements of the sequence, followed by
/// `SeqEnd`. /// `SeqEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let vec = vec!['a', 'b', 'c']; /// let vec = vec!['a', 'b', 'c'];
/// assert_tokens(&vec, &[ /// assert_tokens(
/// Token::Seq { len: Some(3) }, /// &vec,
/// Token::Char('a'), /// &[
/// Token::Char('b'), /// Token::Seq { len: Some(3) },
/// Token::Char('c'), /// Token::Char('a'),
/// Token::SeqEnd, /// Token::Char('b'),
/// ]); /// Token::Char('c'),
/// Token::SeqEnd,
/// ],
/// );
/// ``` /// ```
Seq { len: Option<usize> }, Seq { len: Option<usize> },
@@ -292,16 +304,19 @@ pub enum Token {
/// ///
/// After this header are the elements of the tuple, followed by `TupleEnd`. /// After this header are the elements of the tuple, followed by `TupleEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// let tuple = ('a', 100); /// let tuple = ('a', 100);
/// assert_tokens(&tuple, &[ /// assert_tokens(
/// Token::Tuple { len: 2 }, /// &tuple,
/// Token::Char('a'), /// &[
/// Token::I32(100), /// Token::Tuple { len: 2 },
/// Token::TupleEnd, /// Token::Char('a'),
/// ]); /// Token::I32(100),
/// Token::TupleEnd,
/// ],
/// );
/// ``` /// ```
Tuple { len: usize }, Tuple { len: usize },
@@ -313,8 +328,8 @@ pub enum Token {
/// After this header are the fields of the tuple struct, followed by /// After this header are the fields of the tuple struct, followed by
/// `TupleStructEnd`. /// `TupleStructEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -322,12 +337,15 @@ pub enum Token {
/// struct T(u8, u8); /// struct T(u8, u8);
/// ///
/// let t = T(0, 0); /// let t = T(0, 0);
/// assert_tokens(&t, &[ /// assert_tokens(
/// Token::TupleStruct { name: "T", len: 2 }, /// &t,
/// Token::U8(0), /// &[
/// Token::U8(0), /// Token::TupleStruct { name: "T", len: 2 },
/// Token::TupleStructEnd, /// Token::U8(0),
/// ]); /// Token::U8(0),
/// Token::TupleStructEnd,
/// ],
/// );
/// # } /// # }
/// ``` /// ```
TupleStruct { name: &'static str, len: usize }, TupleStruct { name: &'static str, len: usize },
@@ -340,8 +358,8 @@ pub enum Token {
/// After this header are the fields of the tuple variant, followed by /// After this header are the fields of the tuple variant, followed by
/// `TupleVariantEnd`. /// `TupleVariantEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -351,12 +369,19 @@ pub enum Token {
/// } /// }
/// ///
/// let c = E::C(0, 0); /// let c = E::C(0, 0);
/// assert_tokens(&c, &[ /// assert_tokens(
/// Token::TupleVariant { name: "E", variant: "C", len: 2 }, /// &c,
/// Token::U8(0), /// &[
/// Token::U8(0), /// Token::TupleVariant {
/// Token::TupleVariantEnd, /// name: "E",
/// ]); /// variant: "C",
/// len: 2,
/// },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleVariantEnd,
/// ],
/// );
/// # } /// # }
/// ``` /// ```
TupleVariant { TupleVariant {
@@ -372,7 +397,7 @@ pub enum Token {
/// ///
/// After this header are the entries of the map, followed by `MapEnd`. /// After this header are the entries of the map, followed by `MapEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// use std::collections::BTreeMap; /// use std::collections::BTreeMap;
@@ -381,14 +406,17 @@ pub enum Token {
/// map.insert('A', 65); /// map.insert('A', 65);
/// map.insert('Z', 90); /// map.insert('Z', 90);
/// ///
/// assert_tokens(&map, &[ /// assert_tokens(
/// Token::Map { len: Some(2) }, /// &map,
/// Token::Char('A'), /// &[
/// Token::I32(65), /// Token::Map { len: Some(2) },
/// Token::Char('Z'), /// Token::Char('A'),
/// Token::I32(90), /// Token::I32(65),
/// Token::MapEnd, /// Token::Char('Z'),
/// ]); /// Token::I32(90),
/// Token::MapEnd,
/// ],
/// );
/// ``` /// ```
Map { len: Option<usize> }, Map { len: Option<usize> },
@@ -399,8 +427,8 @@ pub enum Token {
/// ///
/// After this header are the fields of the struct, followed by `StructEnd`. /// After this header are the fields of the struct, followed by `StructEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -411,14 +439,17 @@ pub enum Token {
/// } /// }
/// ///
/// let s = S { a: 0, b: 0 }; /// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[ /// assert_tokens(
/// Token::Struct { name: "S", len: 2 }, /// &s,
/// Token::Str("a"), /// &[
/// Token::U8(0), /// Token::Struct { name: "S", len: 2 },
/// Token::Str("b"), /// Token::Str("a"),
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::Str("b"),
/// ]); /// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// # } /// # }
/// ``` /// ```
Struct { name: &'static str, len: usize }, Struct { name: &'static str, len: usize },
@@ -431,8 +462,8 @@ pub enum Token {
/// After this header are the fields of the struct variant, followed by /// After this header are the fields of the struct variant, followed by
/// `StructVariantEnd`. /// `StructVariantEnd`.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -442,12 +473,19 @@ pub enum Token {
/// } /// }
/// ///
/// let d = E::D { d: 0 }; /// let d = E::D { d: 0 };
/// assert_tokens(&d, &[ /// assert_tokens(
/// Token::StructVariant { name: "E", variant: "D", len: 1 }, /// &d,
/// Token::Str("d"), /// &[
/// Token::U8(0), /// Token::StructVariant {
/// Token::StructVariantEnd, /// name: "E",
/// ]); /// variant: "D",
/// len: 1,
/// },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::StructVariantEnd,
/// ],
/// );
/// # } /// # }
/// ``` /// ```
StructVariant { StructVariant {
@@ -461,8 +499,8 @@ pub enum Token {
/// The header to an enum of the given name. /// The header to an enum of the given name.
/// ///
/// ```edition2018 /// ```edition2021
/// # use serde::{Serialize, Deserialize}; /// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() { /// # fn main() {
@@ -475,38 +513,42 @@ pub enum Token {
/// } /// }
/// ///
/// let a = E::A; /// let a = E::A;
/// assert_tokens(&a, &[ /// assert_tokens(
/// Token::Enum { name: "E" }, /// &a,
/// Token::Str("A"), /// &[Token::Enum { name: "E" }, Token::Str("A"), Token::Unit],
/// Token::Unit, /// );
/// ]);
/// ///
/// let b = E::B(0); /// let b = E::B(0);
/// assert_tokens(&b, &[ /// assert_tokens(
/// Token::Enum { name: "E" }, /// &b,
/// Token::Str("B"), /// &[Token::Enum { name: "E" }, Token::Str("B"), Token::U8(0)],
/// Token::U8(0), /// );
/// ]);
/// ///
/// let c = E::C(0, 0); /// let c = E::C(0, 0);
/// assert_tokens(&c, &[ /// assert_tokens(
/// Token::Enum { name: "E" }, /// &c,
/// Token::Str("C"), /// &[
/// Token::Seq { len: Some(2) }, /// Token::Enum { name: "E" },
/// Token::U8(0), /// Token::Str("C"),
/// Token::U8(0), /// Token::Seq { len: Some(2) },
/// Token::SeqEnd, /// Token::U8(0),
/// ]); /// Token::U8(0),
/// Token::SeqEnd,
/// ],
/// );
/// ///
/// let d = E::D { d: 0 }; /// let d = E::D { d: 0 };
/// assert_tokens(&d, &[ /// assert_tokens(
/// Token::Enum { name: "E" }, /// &d,
/// Token::Str("D"), /// &[
/// Token::Map { len: Some(1) }, /// Token::Enum { name: "E" },
/// Token::Str("d"), /// Token::Str("D"),
/// Token::U8(0), /// Token::Map { len: Some(1) },
/// Token::MapEnd, /// Token::Str("d"),
/// ]); /// Token::U8(0),
/// Token::MapEnd,
/// ],
/// );
/// # } /// # }
/// ``` /// ```
Enum { name: &'static str }, Enum { name: &'static str },
+1 -1
View File
@@ -12,7 +12,7 @@ unstable = ["serde/unstable"]
serde = { path = "../serde" } serde = { path = "../serde" }
[dev-dependencies] [dev-dependencies]
automod = "1.0" automod = "1.0.1"
fnv = "1.0" fnv = "1.0"
rustversion = "1.0" rustversion = "1.0"
serde = { path = "../serde", features = ["rc", "derive"] } serde = { path = "../serde", features = ["rc", "derive"] }
+1 -1
View File
@@ -19,7 +19,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Unit; struct Unit;
+204 -1
View File
@@ -1533,7 +1533,7 @@ fn test_invalid_length_enum() {
Token::TupleVariant { Token::TupleVariant {
name: "InvalidLengthEnum", name: "InvalidLengthEnum",
variant: "B", variant: "B",
len: 3, len: 2,
}, },
Token::I32(1), Token::I32(1),
Token::TupleVariantEnd, Token::TupleVariantEnd,
@@ -2317,6 +2317,53 @@ fn test_internally_tagged_enum_new_type_with_unit() {
); );
} }
#[test]
fn test_adjacently_tagged_enum_bytes() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A { a: i32 },
}
let data = Data::A { a: 0 };
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
assert_de_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Bytes(b"t"),
Token::Str("A"),
Token::Bytes(b"c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
}
#[test] #[test]
fn test_adjacently_tagged_enum_containing_flatten() { fn test_adjacently_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -2395,6 +2442,162 @@ fn test_untagged_enum_containing_flatten() {
); );
} }
#[test]
fn test_partially_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Exp {
Lambda(u32, Box<Exp>),
#[serde(untagged)]
App(Box<Exp>, Box<Exp>),
#[serde(untagged)]
Var(u32),
}
use Exp::*;
let data = Lambda(0, Box::new(App(Box::new(Var(0)), Box::new(Var(0)))));
assert_tokens(
&data,
&[
Token::TupleVariant {
name: "Exp",
variant: "Lambda",
len: 2,
},
Token::U32(0),
Token::Tuple { len: 2 },
Token::U32(0),
Token::U32(0),
Token::TupleEnd,
Token::TupleVariantEnd,
],
);
}
#[test]
fn test_partially_untagged_enum_generic() {
trait Trait<T> {
type Assoc;
type Assoc2;
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum E<A, B, C>
where
A: Trait<C, Assoc2 = B>,
{
A(A::Assoc),
#[serde(untagged)]
B(A::Assoc2),
}
impl<T> Trait<T> for () {
type Assoc = T;
type Assoc2 = bool;
}
type MyE = E<(), bool, u32>;
use E::*;
assert_tokens::<MyE>(&B(true), &[Token::Bool(true)]);
assert_tokens::<MyE>(
&A(5),
&[
Token::NewtypeVariant {
name: "E",
variant: "A",
},
Token::U32(5),
],
);
}
#[test]
fn test_partially_untagged_enum_desugared() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Test {
A(u32, u32),
B(u32),
#[serde(untagged)]
C(u32),
#[serde(untagged)]
D(u32, u32),
}
use Test::*;
mod desugared {
use super::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub(super) enum Test {
A(u32, u32),
B(u32),
}
}
use desugared::Test as TestTagged;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum TestUntagged {
Tagged(TestTagged),
C(u32),
D(u32, u32),
}
impl From<Test> for TestUntagged {
fn from(test: Test) -> Self {
match test {
A(x, y) => TestUntagged::Tagged(TestTagged::A(x, y)),
B(x) => TestUntagged::Tagged(TestTagged::B(x)),
C(x) => TestUntagged::C(x),
D(x, y) => TestUntagged::D(x, y),
}
}
}
fn assert_tokens_desugared(value: Test, tokens: &[Token]) {
assert_tokens(&value, tokens);
let desugared: TestUntagged = value.into();
assert_tokens(&desugared, tokens);
}
assert_tokens_desugared(
A(0, 1),
&[
Token::TupleVariant {
name: "Test",
variant: "A",
len: 2,
},
Token::U32(0),
Token::U32(1),
Token::TupleVariantEnd,
],
);
assert_tokens_desugared(
B(1),
&[
Token::NewtypeVariant {
name: "Test",
variant: "B",
},
Token::U32(1),
],
);
assert_tokens_desugared(C(2), &[Token::U32(2)]);
assert_tokens_desugared(
D(3, 5),
&[
Token::Tuple { len: 2 },
Token::U32(3),
Token::U32(5),
Token::TupleEnd,
],
);
}
#[test] #[test]
fn test_flatten_untagged_enum() { fn test_flatten_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
+17 -13
View File
@@ -4,6 +4,8 @@
clippy::used_underscore_binding clippy::used_underscore_binding
)] )]
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
use serde::de::IntoDeserializer;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
@@ -130,20 +132,22 @@ fn test_cow() {
borrowed: Cow<'b, str>, borrowed: Cow<'b, str>,
} }
let tokens = &[ struct BorrowedStr(&'static str);
Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"),
Token::BorrowedStr("copied"),
Token::Str("borrowed"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
];
let mut de = serde_test::Deserializer::new(tokens); impl<'de> IntoDeserializer<'de> for BorrowedStr {
let cows = Cows::deserialize(&mut de).unwrap(); type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>;
fn into_deserializer(self) -> Self::Deserializer {
BorrowedStrDeserializer::new(self.0)
}
}
let de = MapDeserializer::new(IntoIterator::into_iter([
("copied", BorrowedStr("copied")),
("borrowed", BorrowedStr("borrowed")),
]));
let cows = Cows::deserialize(de).unwrap();
match cows.copied { match cows.copied {
Cow::Owned(ref s) if s == "copied" => {} Cow::Owned(ref s) if s == "copied" => {}
+19 -24
View File
@@ -14,6 +14,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::default::Default; use std::default::Default;
use std::ffi::{CStr, CString, OsString}; use std::ffi::{CStr, CString, OsString};
use std::fmt::Debug; use std::fmt::Debug;
use std::iter;
use std::net; use std::net;
use std::num::{ use std::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
@@ -33,7 +34,7 @@ use std::time::{Duration, UNIX_EPOCH};
use std::sync::atomic::{AtomicI64, AtomicU64}; use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher; use fnv::FnvHasher;
use serde::de::DeserializeOwned; use serde::de::{DeserializeOwned, IntoDeserializer};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, Configure, Token}; use serde_test::{assert_de_tokens, Configure, Token};
@@ -199,12 +200,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
] ]
.into_iter() .into_iter()
.chain(ignorable_tokens.iter().copied()) .chain(ignorable_tokens.iter().copied())
.chain(vec![Token::MapEnd].into_iter()) .chain(iter::once(Token::MapEnd))
.collect(); .collect();
let mut de = serde_test::Deserializer::new(&concated_tokens); let expected = IgnoreBase { a: 1 };
let base = IgnoreBase::deserialize(&mut de).unwrap(); assert_de_tokens(&expected, &concated_tokens);
assert_eq!(base, IgnoreBase { a: 1 });
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -2245,39 +2245,34 @@ fn test_cstr() {
#[test] #[test]
fn test_atomics() { fn test_atomics() {
fn test<L, A, T>(load: L, val: T, token: Token) fn test<L, A, T>(load: L, val: T)
where where
L: Fn(&A, Ordering) -> T, L: Fn(&A, Ordering) -> T,
A: DeserializeOwned, A: DeserializeOwned,
T: PartialEq + Debug, T: PartialEq + Debug + Copy + for<'de> IntoDeserializer<'de>,
{ {
let tokens = &[token]; match A::deserialize(val.into_deserializer()) {
let mut de = serde_test::Deserializer::new(tokens);
match A::deserialize(&mut de) {
Ok(v) => { Ok(v) => {
let loaded = load(&v, Ordering::Relaxed); let loaded = load(&v, Ordering::Relaxed);
assert_eq!(val, loaded); assert_eq!(val, loaded);
} }
Err(e) => panic!("tokens failed to deserialize: {}", e), Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
} }
} }
test(AtomicBool::load, true, Token::Bool(true)); test(AtomicBool::load, true);
test(AtomicI8::load, -127, Token::I8(-127i8)); test(AtomicI8::load, -127i8);
test(AtomicI16::load, -510, Token::I16(-510i16)); test(AtomicI16::load, -510i16);
test(AtomicI32::load, -131072, Token::I32(-131072i32)); test(AtomicI32::load, -131072i32);
test(AtomicIsize::load, -131072isize, Token::I32(-131072)); test(AtomicIsize::load, -131072isize);
test(AtomicU8::load, 127, Token::U8(127u8)); test(AtomicU8::load, 127u8);
test(AtomicU16::load, 510u16, Token::U16(510u16)); test(AtomicU16::load, 510u16);
test(AtomicU32::load, 131072u32, Token::U32(131072u32)); test(AtomicU32::load, 131072u32);
test(AtomicUsize::load, 131072usize, Token::U32(131072)); test(AtomicUsize::load, 131072usize);
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
{ {
test(AtomicI64::load, -8589934592, Token::I64(-8589934592)); test(AtomicI64::load, -8589934592i64);
test(AtomicU64::load, 8589934592u64, Token::U64(8589934592)); test(AtomicU64::load, 8589934592u64);
} }
} }
@@ -0,0 +1,10 @@
use serde_derive::Serialize;
#[derive(Serialize)]
enum E {
#[serde(untagged)]
A(u8),
B(String),
}
fn main() {}
@@ -0,0 +1,5 @@
error: all variants with the #[serde(untagged)] attribute must be placed at the end of the enum
--> tests/ui/enum-representation/partially_tagged_wrong_order.rs:6:5
|
6 | A(u8),
| ^
+1 -1
View File
@@ -1,4 +1,4 @@
use serde_derive::{Serialize, Deserialize}; use serde_derive::{Deserialize, Serialize};
mod remote { mod remote {
pub struct S { pub struct S {
+1 -1
View File
@@ -1,4 +1,4 @@
use serde_derive::{Serialize, Deserialize}; use serde_derive::{Deserialize, Serialize};
mod remote { mod remote {
pub struct S { pub struct S {