Compare commits

...

27 Commits

Author SHA1 Message Date
David Tolnay 1b4da41f97 Release 1.0.207 2024-08-12 13:06:46 -07:00
David Tolnay f61d452814 Touch up PR 2795 2024-08-12 13:03:10 -07:00
David Tolnay f9866097a0 Merge pull request #2795 from Mingun/has-flatten-rework
`has_flatten` rework
2024-08-12 13:02:58 -07:00
Mingun 77a6a9d4e1 Take into account only not skipped flatten fields when choose serialization form
Consequence: `FlattenSkipSerializing`
- uses `serialize_struct` instead of `serialize_map`
2024-08-11 20:12:09 +05:00
Mingun 547d843cca Remove dead code - serialize_struct_as_map always called when cattrs.has_flatten()==true 2024-08-11 20:12:08 +05:00
Mingun 005cb84593 Fail with an understandable message is number of fields for serialization is too many 2024-08-11 20:12:07 +05:00
Mingun fd5b5e9aa5 Correctly calculate has_flatten attribute in all cases for deserialization
Consequence: `FlattenSkipDeserializing[DenyUnknown]`
- does not collect data in Field, because do not read them anyway
- gets `deserialize_in_place` method
- gets ability to deserialize from sequence (visit_seq method)
- uses `deserialize_struct` instead of `deserialize_map`
2024-08-11 20:01:33 +05:00
Mingun 0647a7c1fe Fix creating and filling a collections that was not read 2024-08-11 20:01:00 +05:00
David Tolnay 85c73ef8de Release 1.0.206 2024-08-11 00:08:37 -07:00
David Tolnay 5ba1796a7e Resolve doc_markdown pedantic lint on regression test function
warning: you should put bare URLs between `<`/`>` or make a proper Markdown link
        --> test_suite/tests/test_annotations.rs:2383:25
         |
    2383 | /// Regression test for https://github.com/serde-rs/serde/issues/1904
         |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<https://github.com/serde-rs/serde/issues/1904>`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
         = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic`
         = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]`
2024-08-11 00:08:16 -07:00
David Tolnay e52b7b380f Touch up PR 2567 2024-08-11 00:05:56 -07:00
David Tolnay 84c7419652 Merge pull request #2794 from dtolnay/neverread
Temporarily ignore collection_is_never_read on FlattenSkipDeserializing
2024-08-11 00:05:31 -07:00
David Tolnay 536221b1f9 Temporarily ignore collection_is_never_read on FlattenSkipDeserializing
error: collection is never read
       --> test_suite/tests/test_gen.rs:723:25
        |
    723 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:23:9
        |
    23  | #![deny(clippy::collection_is_never_read)]
        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2024-08-10 23:59:23 -07:00
David Tolnay fc55ac70d3 Merge pull request #2567 from Mingun/fix-2565
Correctly process flatten fields in enum variants
2024-08-10 23:28:22 -07:00
Mingun 2afe5b4ef9 Add regression test for issue #2792 2024-08-10 21:29:39 +05:00
Mingun b4ec2595c9 Correctly process flatten fields in enum variants
- Fix incorrect deserialization of variants that doesn't contain flatten field when other contains
- Fix a panic when deriving `Deserialize` for an enum with tuple and struct with flatten field

Fixes (2):
    regression::issue2565::simple_variant
    regression::issue1904 (compilation)
2024-08-09 19:59:23 +05:00
Mingun c3ac7b675a Add regression test for issue #1904
Currently panics in derive:

error: proc-macro derive panicked
    --> test_suite\tests\test_annotations.rs:2386:25
     |
2386 |     #[derive(Serialize, Deserialize, PartialEq, Debug)]
     |                         ^^^^^^^^^^^
     |
     = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
  --> test_suite\tests\regression\issue1904.rs:57:10
   |
57 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
   = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
  --> test_suite\tests\regression\issue1904.rs:47:10
   |
47 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
   = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
  --> test_suite\tests\regression\issue1904.rs:37:10
   |
37 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
   = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
  --> test_suite\tests\regression\issue1904.rs:27:10
   |
27 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
   = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
  --> test_suite\tests\regression\issue1904.rs:16:10
   |
16 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
   = help: message: assertion failed: !cattrs.has_flatten()

error: proc-macro derive panicked
 --> test_suite\tests\regression\issue1904.rs:7:10
  |
7 | #[derive(Deserialize)]
  |          ^^^^^^^^^^^
  |
  = help: message: assertion failed: !cattrs.has_flatten()
2024-08-09 19:55:56 +05:00
Mingun 24614e44bf Add regression test for issue #2565
failures (1):
    regression::issue2565::simple_variant
2024-08-09 19:53:14 +05:00
David Tolnay 9b868ef831 Release 1.0.205 2024-08-07 18:53:21 -07:00
David Tolnay c3eaf76430 Merge pull request #2791 from dtolnay/flatten
Skip collecting unmatched fields in variants that do not use flatten
2024-08-07 18:52:21 -07:00
David Tolnay 32958dec3b Skip collecting unmatched fields in variants that do not use flatten 2024-08-07 18:43:47 -07:00
David Tolnay d64a97ba1e Ignore confusable_idents warning in test
error: found both `σ` and `o` as identifiers, which look alike
       --> test_suite/tests/test_gen.rs:734:13
        |
    292 |         σ: f64,
        |         - other identifier used here
    ...
    734 |             o: T,
        |             ^ this identifier can be confused with `σ`
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[deny(confusable_idents)]` implied by `#[deny(warnings)]`
2024-08-07 18:19:51 -07:00
David Tolnay c3df3372a1 Add test of flatten in enum
error: collection is never read
       --> test_suite/tests/test_gen.rs:728:25
        |
    728 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2024-08-07 18:19:17 -07:00
David Tolnay 8764353fe2 Enable collection_is_never_read nursury lint in test
error: collection is never read
       --> test_suite/tests/test_gen.rs:722:25
        |
    722 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:22:9
        |
    22  | #![deny(clippy::collection_is_never_read)]
        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2024-08-07 18:16:55 -07:00
David Tolnay e08c5de5dd Merge pull request #2785 from Mingun/serialize_entry-in-flatten-newtype-variant
Use serialize_entry instead of serialize_key + serialize_value when serialize flatten newtype enum variant
2024-08-05 00:17:58 -07:00
Mingun bc5af506bd Use serialize_entry instead of serialize_key + serialize_value when serialize flatten newtype enum variant
Serializers that reimplements serialize_entry will get benefits from that
2024-08-03 14:49:38 +05:00
David Tolnay 28a092261b Work around test suite dead code warnings in nightly-2024-07-07
warning: struct `Cows` is never constructed
       --> test_suite/tests/test_borrow.rs:165:12
        |
    165 |     struct Cows<'a, 'b> {
        |            ^^^^

    warning: struct `Wrap` is never constructed
       --> test_suite/tests/test_borrow.rs:181:12
        |
    181 |     struct Wrap<'a, 'b> {
        |            ^^^^

    warning: struct `StructSkipDefaultGeneric` is never constructed
      --> test_suite/tests/test_de.rs:96:8
       |
    96 | struct StructSkipDefaultGeneric<T> {
       |        ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `NonAsciiIdents` is never constructed
       --> test_suite/tests/test_gen.rs:290:12
        |
    290 |     struct NonAsciiIdents {
        |            ^^^^^^^^^^^^^^
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[warn(dead_code)]` implied by `#[warn(warnings)]`

    warning: struct `EmptyBraced` is never constructed
       --> test_suite/tests/test_gen.rs:295:12
        |
    295 |     struct EmptyBraced {}
        |            ^^^^^^^^^^^

    warning: struct `EmptyBracedDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:299:12
        |
    299 |     struct EmptyBracedDenyUnknown {}
        |            ^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `BracedSkipAll` is never constructed
       --> test_suite/tests/test_gen.rs:302:12
        |
    302 |     struct BracedSkipAll {
        |            ^^^^^^^^^^^^^

    warning: struct `BracedSkipAllDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:309:12
        |
    309 |     struct BracedSkipAllDenyUnknown {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `EmptyTuple` is never constructed
       --> test_suite/tests/test_gen.rs:315:12
        |
    315 |     struct EmptyTuple();
        |            ^^^^^^^^^^

    warning: struct `EmptyTupleDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:319:12
        |
    319 |     struct EmptyTupleDenyUnknown();
        |            ^^^^^^^^^^^^^^^^^^^^^

    warning: struct `TupleSkipAll` is never constructed
       --> test_suite/tests/test_gen.rs:322:12
        |
    322 |     struct TupleSkipAll(#[serde(skip_deserializing)] u8);
        |            ^^^^^^^^^^^^

    warning: struct `TupleSkipAllDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:326:12
        |
    326 |     struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
        |            ^^^^^^^^^^^^^^^^^^^^^^^

    warning: enum `EmptyEnum` is never used
       --> test_suite/tests/test_gen.rs:329:10
        |
    329 |     enum EmptyEnum {}
        |          ^^^^^^^^^

    warning: enum `EmptyEnumDenyUnknown` is never used
       --> test_suite/tests/test_gen.rs:333:10
        |
    333 |     enum EmptyEnumDenyUnknown {}
        |          ^^^^^^^^^^^^^^^^^^^^

    warning: enum `EnumSkipAll` is never used
       --> test_suite/tests/test_gen.rs:336:10
        |
    336 |     enum EnumSkipAll {
        |          ^^^^^^^^^^^

    warning: enum `EmptyVariants` is never used
       --> test_suite/tests/test_gen.rs:343:10
        |
    343 |     enum EmptyVariants {
        |          ^^^^^^^^^^^^^

    warning: enum `EmptyVariantsDenyUnknown` is never used
       --> test_suite/tests/test_gen.rs:355:10
        |
    355 |     enum EmptyVariantsDenyUnknown {
        |          ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `UnitDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:367:12
        |
    367 |     struct UnitDenyUnknown;
        |            ^^^^^^^^^^^^^^^

    warning: struct `EmptyArray` is never constructed
       --> test_suite/tests/test_gen.rs:370:12
        |
    370 |     struct EmptyArray {
        |            ^^^^^^^^^^

    warning: enum `Or` is never used
       --> test_suite/tests/test_gen.rs:374:10
        |
    374 |     enum Or<A, B> {
        |          ^^

    warning: enum `OrDef` is never used
       --> test_suite/tests/test_gen.rs:381:10
        |
    381 |     enum OrDef<A, B> {
        |          ^^^^^

    warning: struct `Str` is never constructed
       --> test_suite/tests/test_gen.rs:386:12
        |
    386 |     struct Str<'a>(&'a str);
        |            ^^^

    warning: struct `StrDef` is never constructed
       --> test_suite/tests/test_gen.rs:390:12
        |
    390 |     struct StrDef<'a>(&'a str);
        |            ^^^^^^

    warning: struct `Remote` is never constructed
       --> test_suite/tests/test_gen.rs:393:12
        |
    393 |     struct Remote<'a> {
        |            ^^^^^^

    warning: enum `BorrowVariant` is never used
       --> test_suite/tests/test_gen.rs:401:10
        |
    401 |     enum BorrowVariant<'a> {
        |          ^^^^^^^^^^^^^

    warning: struct `RemoteVisibility` is never constructed
       --> test_suite/tests/test_gen.rs:418:12
        |
    418 |     struct RemoteVisibility {
        |            ^^^^^^^^^^^^^^^^

    warning: struct `FlattenDenyUnknown` is never constructed
       --> test_suite/tests/test_gen.rs:551:12
        |
    551 |     struct FlattenDenyUnknown<T> {
        |            ^^^^^^^^^^^^^^^^^^

    warning: struct `StaticStrStruct` is never constructed
       --> test_suite/tests/test_gen.rs:557:12
        |
    557 |     struct StaticStrStruct<'a> {
        |            ^^^^^^^^^^^^^^^

    warning: struct `StaticStrTupleStruct` is never constructed
       --> test_suite/tests/test_gen.rs:563:12
        |
    563 |     struct StaticStrTupleStruct<'a>(&'a str, &'static str);
        |            ^^^^^^^^^^^^^^^^^^^^

    warning: struct `StaticStrNewtypeStruct` is never constructed
       --> test_suite/tests/test_gen.rs:566:12
        |
    566 |     struct StaticStrNewtypeStruct(&'static str);
        |            ^^^^^^^^^^^^^^^^^^^^^^

    warning: enum `StaticStrEnum` is never used
       --> test_suite/tests/test_gen.rs:569:10
        |
    569 |     enum StaticStrEnum<'a> {
        |          ^^^^^^^^^^^^^

    warning: enum `AdjacentlyTaggedVoid` is never used
       --> test_suite/tests/test_gen.rs:652:10
        |
    652 |     enum AdjacentlyTaggedVoid {}
        |          ^^^^^^^^^^^^^^^^^^^^

    warning: struct `ImplicitlyBorrowedOption` is never constructed
       --> test_suite/tests/test_gen.rs:665:12
        |
    665 |     struct ImplicitlyBorrowedOption<'a> {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: enum `UntaggedNewtypeVariantWith` is never used
       --> test_suite/tests/test_gen.rs:672:10
        |
    672 |     enum UntaggedNewtypeVariantWith {
        |          ^^^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `TransparentWith` is never constructed
       --> test_suite/tests/test_gen.rs:682:12
        |
    682 |     struct TransparentWith {
        |            ^^^^^^^^^^^^^^^

    warning: struct `FlattenSkipSerializing` is never constructed
       --> test_suite/tests/test_gen.rs:712:12
        |
    712 |     struct FlattenSkipSerializing<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `FlattenSkipSerializingIf` is never constructed
       --> test_suite/tests/test_gen.rs:719:12
        |
    719 |     struct FlattenSkipSerializingIf<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `FlattenSkipDeserializing` is never constructed
       --> test_suite/tests/test_gen.rs:725:12
        |
    725 |     struct FlattenSkipDeserializing<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^

    warning: enum `Message` is never used
       --> test_suite/tests/test_gen.rs:732:10
        |
    732 |     enum Message {
        |          ^^^^^^^

    warning: struct `MacroRules` is never constructed
       --> test_suite/tests/test_gen.rs:751:20
        |
    751 |             struct MacroRules<'a> {
        |                    ^^^^^^^^^^
    ...
    758 |     deriving!(&'a str);
        |     ------------------ in this macro invocation
        |
        = note: this warning originates in the macro `deriving` (in Nightly builds, run with -Z macro-backtrace for more info)

    warning: struct `BorrowLifetimeInsideMacro` is never constructed
       --> test_suite/tests/test_gen.rs:767:12
        |
    767 |     struct BorrowLifetimeInsideMacro<'a> {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^

    warning: struct `GenericUnitStruct` is never constructed
       --> test_suite/tests/test_gen.rs:782:12
        |
    782 |     struct GenericUnitStruct<const N: usize>;
        |            ^^^^^^^^^^^^^^^^^

    warning: enum `InternallyTagged` is never used
       --> test_suite/tests/test_gen.rs:869:6
        |
    869 | enum InternallyTagged {
        |      ^^^^^^^^^^^^^^^^

    warning: function `deserialize_generic` is never used
       --> test_suite/tests/test_gen.rs:880:4
        |
    880 | fn deserialize_generic<'de, T, D>(deserializer: D) -> StdResult<T, D::Error>
        |    ^^^^^^^^^^^^^^^^^^^

    warning: struct `Restricted` is never constructed
       --> test_suite/tests/test_gen.rs:643:20
        |
    643 |             struct Restricted {
        |                    ^^^^^^^^^^

    warning: struct `Test` is never constructed
      --> test_suite/tests/test_remote.rs:95:8
       |
    95 | struct Test {
       |        ^^^^

    warning: struct `UnitDef` is never constructed
       --> test_suite/tests/test_remote.rs:135:8
        |
    135 | struct UnitDef;
        |        ^^^^^^^

    warning: struct `PrimitivePubDef` is never constructed
       --> test_suite/tests/test_remote.rs:143:8
        |
    143 | struct PrimitivePubDef(u8);
        |        ^^^^^^^^^^^^^^^

    warning: struct `NewtypePubDef` is never constructed
       --> test_suite/tests/test_remote.rs:151:8
        |
    151 | struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
        |        ^^^^^^^^^^^^^

    warning: struct `TuplePubDef` is never constructed
       --> test_suite/tests/test_remote.rs:162:8
        |
    162 | struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
        |        ^^^^^^^^^^^

    warning: struct `StructPubDef` is never constructed
       --> test_suite/tests/test_remote.rs:177:8
        |
    177 | struct StructPubDef {
        |        ^^^^^^^^^^^^

    warning: struct `StructConcrete` is never constructed
       --> test_suite/tests/test_remote.rs:193:8
        |
    193 | struct StructConcrete {
        |        ^^^^^^^^^^^^^^

    warning: enum `EnumConcrete` is never used
       --> test_suite/tests/test_remote.rs:199:6
        |
    199 | enum EnumConcrete {
        |      ^^^^^^^^^^^^

    warning: enum `ErrorKind` is never used
       --> test_suite/tests/test_remote.rs:204:6
        |
    204 | enum ErrorKind {
        |      ^^^^^^^^^

    warning: enum `ErrorKindDef` is never used
       --> test_suite/tests/test_remote.rs:214:6
        |
    214 | enum ErrorKindDef {
        |      ^^^^^^^^^^^^

    warning: struct `PrimitivePub` is never constructed
      --> test_suite/tests/test_remote.rs:10:16
       |
    10 |     pub struct PrimitivePub(pub u8);
       |                ^^^^^^^^^^^^

    warning: struct `NewtypePub` is never constructed
      --> test_suite/tests/test_remote.rs:14:16
       |
    14 |     pub struct NewtypePub(pub Unit);
       |                ^^^^^^^^^^

    warning: struct `TuplePub` is never constructed
      --> test_suite/tests/test_remote.rs:18:16
       |
    18 |     pub struct TuplePub(pub u8, pub Unit);
       |                ^^^^^^^^

    warning: struct `StructPub` is never constructed
      --> test_suite/tests/test_remote.rs:25:16
       |
    25 |     pub struct StructPub {
       |                ^^^^^^^^^

    warning: enum `EnumGeneric` is never used
      --> test_suite/tests/test_remote.rs:89:14
       |
    89 |     pub enum EnumGeneric<T> {
       |              ^^^^^^^^^^^

    warning: struct `Tuple` is never constructed
      --> test_suite/tests/test_self.rs:44:12
       |
    44 |     struct Tuple(
       |            ^^^^^

    warning: associated items `ASSOC` and `assoc` are never used
      --> test_suite/tests/test_self.rs:52:15
       |
    51 |     impl Tuple {
       |     ---------- associated items in this implementation
    52 |         const ASSOC: usize = 1;
       |               ^^^^^
    53 |         const fn assoc() -> usize {
       |                  ^^^^^

    warning: enum `Enum` is never used
      --> test_suite/tests/test_self.rs:63:10
       |
    63 |     enum Enum {
       |          ^^^^

    warning: associated items `ASSOC` and `assoc` are never used
      --> test_suite/tests/test_self.rs:79:15
       |
    78 |     impl Enum {
       |     --------- associated items in this implementation
    79 |         const ASSOC: usize = 1;
       |               ^^^^^
    80 |         const fn assoc() -> usize {
       |                  ^^^^^

    warning: struct `Unit` is never constructed
      --> test_suite/no_std/src/main.rs:26:8
       |
    26 | struct Unit;
       |        ^^^^

    warning: struct `Newtype` is never constructed
      --> test_suite/no_std/src/main.rs:29:8
       |
    29 | struct Newtype(u8);
       |        ^^^^^^^

    warning: struct `Tuple` is never constructed
      --> test_suite/no_std/src/main.rs:32:8
       |
    32 | struct Tuple(u8, u8);
       |        ^^^^^

    warning: struct `Struct` is never constructed
      --> test_suite/no_std/src/main.rs:35:8
       |
    35 | struct Struct {
       |        ^^^^^^

    warning: enum `Enum` is never used
      --> test_suite/no_std/src/main.rs:40:6
       |
    40 | enum Enum {
       |      ^^^^
2024-07-06 19:26:29 -07:00
19 changed files with 350 additions and 139 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.204" version = "1.0.207"
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", "no-std::no-alloc"] categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -37,7 +37,7 @@ rustdoc-args = ["--generate-link-to-definition"]
# is compatible with exactly one serde release because the generated code # is compatible with exactly one serde release because the generated code
# involves nonpublic APIs which are not bound by semver. # involves nonpublic APIs which are not bound by semver.
[target.'cfg(any())'.dependencies] [target.'cfg(any())'.dependencies]
serde_derive = { version = "=1.0.204", path = "../serde_derive" } serde_derive = { version = "=1.0.207", path = "../serde_derive" }
### FEATURES ################################################################# ### FEATURES #################################################################
+1 -1
View File
@@ -95,7 +95,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.204")] #![doc(html_root_url = "https://docs.rs/serde/1.0.207")]
// 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)]
// Show which crate feature enables conditionally compiled APIs in documentation. // Show which crate feature enables conditionally compiled APIs in documentation.
+1 -2
View File
@@ -1125,8 +1125,7 @@ where
where where
T: ?Sized + Serialize, T: ?Sized + Serialize,
{ {
tri!(self.0.serialize_key(variant)); self.0.serialize_entry(variant, value)
self.0.serialize_value(value)
} }
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.204" version = "1.0.207"
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", "no-std::no-alloc"] 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)]"
+52 -28
View File
@@ -461,7 +461,10 @@ fn deserialize_tuple(
cattrs: &attr::Container, cattrs: &attr::Container,
form: TupleForm, form: TupleForm,
) -> Fragment { ) -> Fragment {
assert!(!cattrs.has_flatten()); assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields let field_count = fields
.iter() .iter()
@@ -579,7 +582,10 @@ fn deserialize_tuple_in_place(
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
assert!(!cattrs.has_flatten()); assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields let field_count = fields
.iter() .iter()
@@ -958,13 +964,15 @@ fn deserialize_struct(
) )
}) })
.collect(); .collect();
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
let has_flatten = has_flatten(fields);
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, has_flatten);
// 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 form { let visit_seq = match form {
StructForm::Untagged(..) => None, StructForm::Untagged(..) => None,
_ if cattrs.has_flatten() => None, _ if has_flatten => None,
_ => { _ => {
let mut_seq = if field_names_idents.is_empty() { let mut_seq = if field_names_idents.is_empty() {
quote!(_) quote!(_)
@@ -987,10 +995,16 @@ fn deserialize_struct(
}) })
} }
}; };
let visit_map = Stmts(deserialize_map(&type_path, params, fields, cattrs)); let visit_map = Stmts(deserialize_map(
&type_path,
params,
fields,
cattrs,
has_flatten,
));
let visitor_seed = match form { let visitor_seed = match form {
StructForm::ExternallyTagged(..) if cattrs.has_flatten() => Some(quote! { StructForm::ExternallyTagged(..) if 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;
@@ -1005,7 +1019,7 @@ fn deserialize_struct(
_ => None, _ => None,
}; };
let fields_stmt = if cattrs.has_flatten() { let fields_stmt = if has_flatten {
None None
} else { } else {
let field_names = field_names_idents let field_names = field_names_idents
@@ -1025,7 +1039,7 @@ fn deserialize_struct(
} }
}; };
let dispatch = match form { let dispatch = match form {
StructForm::Struct if cattrs.has_flatten() => quote! { StructForm::Struct if has_flatten => quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
}, },
StructForm::Struct => { StructForm::Struct => {
@@ -1034,7 +1048,7 @@ fn deserialize_struct(
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
} }
} }
StructForm::ExternallyTagged(_) if cattrs.has_flatten() => quote! { StructForm::ExternallyTagged(_) if has_flatten => quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
}, },
StructForm::ExternallyTagged(_) => quote! { StructForm::ExternallyTagged(_) => quote! {
@@ -1091,7 +1105,7 @@ fn deserialize_struct_in_place(
) -> Option<Fragment> { ) -> Option<Fragment> {
// for now we do not support in_place deserialization for structs that // for now we do not support in_place deserialization for structs that
// are represented as map. // are represented as map.
if cattrs.has_flatten() { if has_flatten(fields) {
return None; return None;
} }
@@ -1116,7 +1130,7 @@ fn deserialize_struct_in_place(
}) })
.collect(); .collect();
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs); let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, false);
let mut_seq = if field_names_idents.is_empty() { let mut_seq = if field_names_idents.is_empty() {
quote!(_) quote!(_)
@@ -1210,10 +1224,7 @@ fn deserialize_homogeneous_enum(
} }
} }
fn prepare_enum_variant_enum( fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
variants: &[Variant],
cattrs: &attr::Container,
) -> (TokenStream, Stmts) {
let mut deserialized_variants = variants let mut deserialized_variants = variants
.iter() .iter()
.enumerate() .enumerate()
@@ -1247,7 +1258,7 @@ fn prepare_enum_variant_enum(
let variant_visitor = Stmts(deserialize_generated_identifier( let variant_visitor = Stmts(deserialize_generated_identifier(
&variant_names_idents, &variant_names_idents,
cattrs, false, // variant identifiers do not depend on the presence of flatten fields
true, true,
None, None,
fallthrough, fallthrough,
@@ -1270,7 +1281,7 @@ fn deserialize_externally_tagged_enum(
let expecting = format!("enum {}", params.type_name()); let expecting = format!("enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting); let expecting = cattrs.expecting().unwrap_or(&expecting);
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
let variant_arms = variants let variant_arms = variants
@@ -1355,7 +1366,7 @@ fn deserialize_internally_tagged_enum(
cattrs: &attr::Container, cattrs: &attr::Container,
tag: &str, tag: &str,
) -> Fragment { ) -> Fragment {
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
let variant_arms = variants let variant_arms = variants
@@ -1409,7 +1420,7 @@ fn deserialize_adjacently_tagged_enum(
split_with_de_lifetime(params); split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
let variant_arms: &Vec<_> = &variants let variant_arms: &Vec<_> = &variants
.iter() .iter()
@@ -1985,7 +1996,7 @@ fn deserialize_untagged_newtype_variant(
fn deserialize_generated_identifier( fn deserialize_generated_identifier(
fields: &[(&str, Ident, &BTreeSet<String>)], fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container, has_flatten: bool,
is_variant: bool, is_variant: bool,
ignore_variant: Option<TokenStream>, ignore_variant: Option<TokenStream>,
fallthrough: Option<TokenStream>, fallthrough: Option<TokenStream>,
@@ -1999,11 +2010,11 @@ fn deserialize_generated_identifier(
is_variant, is_variant,
fallthrough, fallthrough,
None, None,
!is_variant && cattrs.has_flatten(), !is_variant && has_flatten,
None, None,
)); ));
let lifetime = if !is_variant && cattrs.has_flatten() { let lifetime = if !is_variant && has_flatten {
Some(quote!(<'de>)) Some(quote!(<'de>))
} else { } else {
None None
@@ -2043,8 +2054,9 @@ fn deserialize_generated_identifier(
fn deserialize_field_identifier( fn deserialize_field_identifier(
fields: &[(&str, Ident, &BTreeSet<String>)], fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container, cattrs: &attr::Container,
has_flatten: bool,
) -> Stmts { ) -> Stmts {
let (ignore_variant, fallthrough) = if cattrs.has_flatten() { let (ignore_variant, fallthrough) = if has_flatten {
let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),);
let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value))); let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value)));
(Some(ignore_variant), Some(fallthrough)) (Some(ignore_variant), Some(fallthrough))
@@ -2058,7 +2070,7 @@ fn deserialize_field_identifier(
Stmts(deserialize_generated_identifier( Stmts(deserialize_generated_identifier(
fields, fields,
cattrs, has_flatten,
false, false,
ignore_variant, ignore_variant,
fallthrough, fallthrough,
@@ -2460,6 +2472,7 @@ fn deserialize_map(
params: &Parameters, params: &Parameters,
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
has_flatten: bool,
) -> Fragment { ) -> Fragment {
// Create the field names for the fields. // Create the field names for the fields.
let fields_names: Vec<_> = fields let fields_names: Vec<_> = fields
@@ -2480,7 +2493,7 @@ fn deserialize_map(
}); });
// Collect contents for flatten fields into a buffer // Collect contents for flatten fields into a buffer
let let_collect = if cattrs.has_flatten() { let let_collect = if has_flatten {
Some(quote! { Some(quote! {
let mut __collect = _serde::__private::Vec::<_serde::__private::Option<( let mut __collect = _serde::__private::Vec::<_serde::__private::Option<(
_serde::__private::de::Content, _serde::__private::de::Content,
@@ -2532,7 +2545,7 @@ fn deserialize_map(
}); });
// Visit ignored values to consume them // Visit ignored values to consume them
let ignored_arm = if cattrs.has_flatten() { let ignored_arm = if has_flatten {
Some(quote! { Some(quote! {
__Field::__other(__name) => { __Field::__other(__name) => {
__collect.push(_serde::__private::Some(( __collect.push(_serde::__private::Some((
@@ -2602,7 +2615,7 @@ fn deserialize_map(
} }
}); });
let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { let collected_deny_unknown_fields = if has_flatten && cattrs.deny_unknown_fields() {
Some(quote! { Some(quote! {
if let _serde::__private::Some(_serde::__private::Some((__key, _))) = if let _serde::__private::Some(_serde::__private::Some((__key, _))) =
__collect.into_iter().filter(_serde::__private::Option::is_some).next() __collect.into_iter().filter(_serde::__private::Option::is_some).next()
@@ -2678,7 +2691,10 @@ fn deserialize_map_in_place(
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
assert!(!cattrs.has_flatten()); assert!(
!has_flatten(fields),
"inplace deserialization of maps does not support flatten fields"
);
// Create the field names for the fields. // Create the field names for the fields.
let fields_names: Vec<_> = fields let fields_names: Vec<_> = fields
@@ -3011,6 +3027,14 @@ fn effective_style(variant: &Variant) -> Style {
} }
} }
/// True if there is any field with a `#[serde(flatten)]` attribute, other than
/// fields which are skipped.
fn has_flatten(fields: &[Field]) -> bool {
fields
.iter()
.any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing())
}
struct DeImplGenerics<'a>(&'a Parameters); struct DeImplGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
struct InPlaceImplGenerics<'a>(&'a Parameters); struct InPlaceImplGenerics<'a>(&'a Parameters);
+1 -12
View File
@@ -63,7 +63,7 @@ impl<'a> Container<'a> {
item: &'a syn::DeriveInput, item: &'a syn::DeriveInput,
derive: Derive, derive: Derive,
) -> Option<Container<'a>> { ) -> Option<Container<'a>> {
let mut attrs = attr::Container::from_ast(cx, item); let attrs = attr::Container::from_ast(cx, item);
let mut data = match &item.data { let mut data = match &item.data {
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())), syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
@@ -77,15 +77,11 @@ impl<'a> Container<'a> {
} }
}; };
let mut has_flatten = false;
match &mut data { match &mut data {
Data::Enum(variants) => { Data::Enum(variants) => {
for variant in variants { for variant in variants {
variant.attrs.rename_by_rules(attrs.rename_all_rules()); variant.attrs.rename_by_rules(attrs.rename_all_rules());
for field in &mut variant.fields { for field in &mut variant.fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rules( field.attrs.rename_by_rules(
variant variant
.attrs .attrs
@@ -97,18 +93,11 @@ impl<'a> Container<'a> {
} }
Data::Struct(_, fields) => { Data::Struct(_, fields) => {
for field in fields { for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rules(attrs.rename_all_rules()); field.attrs.rename_by_rules(attrs.rename_all_rules());
} }
} }
} }
if has_flatten {
attrs.mark_has_flatten();
}
let mut item = Container { let mut item = Container {
ident: item.ident.clone(), ident: item.ident.clone(),
attrs, attrs,
-10
View File
@@ -216,7 +216,6 @@ pub struct Container {
type_into: Option<syn::Type>, type_into: Option<syn::Type>,
remote: Option<syn::Path>, remote: Option<syn::Path>,
identifier: Identifier, identifier: Identifier,
has_flatten: bool,
serde_path: Option<syn::Path>, serde_path: Option<syn::Path>,
is_packed: bool, is_packed: bool,
/// Error message generated when type can't be deserialized /// Error message generated when type can't be deserialized
@@ -587,7 +586,6 @@ impl Container {
type_into: type_into.get(), type_into: type_into.get(),
remote: remote.get(), remote: remote.get(),
identifier: decide_identifier(cx, item, field_identifier, variant_identifier), identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
has_flatten: false,
serde_path: serde_path.get(), serde_path: serde_path.get(),
is_packed, is_packed,
expecting: expecting.get(), expecting: expecting.get(),
@@ -655,14 +653,6 @@ impl Container {
self.identifier self.identifier
} }
pub fn has_flatten(&self) -> bool {
self.has_flatten
}
pub fn mark_has_flatten(&mut self) {
self.has_flatten = true;
}
pub fn custom_serde_path(&self) -> Option<&syn::Path> { pub fn custom_serde_path(&self) -> Option<&syn::Path> {
self.serde_path.as_ref() self.serde_path.as_ref()
} }
+1 -1
View File
@@ -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.204")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.207")]
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))] #![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
+12 -21
View File
@@ -289,9 +289,18 @@ fn serialize_tuple_struct(
} }
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
assert!(fields.len() as u64 <= u64::from(u32::MAX)); assert!(
fields.len() as u64 <= u64::from(u32::MAX),
"too many fields in {}: {}, maximum supported count is {}",
cattrs.name().serialize_name(),
fields.len(),
u32::MAX,
);
if cattrs.has_flatten() { let has_non_skipped_flatten = fields
.iter()
.any(|field| field.attrs.flatten() && !field.attrs.skip_serializing());
if has_non_skipped_flatten {
serialize_struct_as_map(params, fields, cattrs) serialize_struct_as_map(params, fields, cattrs)
} else { } else {
serialize_struct_as_struct(params, fields, cattrs) serialize_struct_as_struct(params, fields, cattrs)
@@ -370,26 +379,8 @@ fn serialize_struct_as_map(
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
let len = if cattrs.has_flatten() {
quote!(_serde::__private::None)
} else {
let len = serialized_fields
.map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let field_expr = get_member(params, field, &field.member);
quote!(if #path(#field_expr) { 0 } else { 1 })
}
})
.fold(
quote!(#tag_field_exists as usize),
|sum, expr| quote!(#sum + #expr),
);
quote!(_serde::__private::Some(#len))
};
quote_block! { quote_block! {
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?; let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::__private::None)?;
#tag_field #tag_field
#(#serialize_fields)* #(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state) _serde::ser::SerializeMap::end(__serde_state)
+5 -5
View File
@@ -23,21 +23,21 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Unit; pub struct Unit;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Newtype(u8); pub struct Newtype(u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Tuple(u8, u8); pub struct Tuple(u8, u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Struct { pub struct Struct {
f: u8, f: u8,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum Enum { pub enum Enum {
Unit, Unit,
Newtype(u8), Newtype(u8),
Tuple(u8, u8), Tuple(u8, u8),
+66
View File
@@ -0,0 +1,66 @@
#![allow(dead_code)] // we do not read enum fields
use serde_derive::Deserialize;
#[derive(Deserialize)]
pub struct Nested;
#[derive(Deserialize)]
pub enum ExternallyTagged1 {
Tuple(f64, String),
Flatten {
#[serde(flatten)]
nested: Nested,
},
}
#[derive(Deserialize)]
pub enum ExternallyTagged2 {
Flatten {
#[serde(flatten)]
nested: Nested,
},
Tuple(f64, String),
}
// Internally tagged enums cannot contain tuple variants so not tested here
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
pub enum AdjacentlyTagged1 {
Tuple(f64, String),
Flatten {
#[serde(flatten)]
nested: Nested,
},
}
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
pub enum AdjacentlyTagged2 {
Flatten {
#[serde(flatten)]
nested: Nested,
},
Tuple(f64, String),
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum Untagged1 {
Tuple(f64, String),
Flatten {
#[serde(flatten)]
nested: Nested,
},
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum Untagged2 {
Flatten {
#[serde(flatten)]
nested: Nested,
},
Tuple(f64, String),
}
+41
View File
@@ -0,0 +1,41 @@
use serde_derive::{Serialize, Deserialize};
use serde_test::{assert_tokens, Token};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Enum {
Simple {
a: i32,
},
Flatten {
#[serde(flatten)]
flatten: (),
a: i32,
},
}
#[test]
fn simple_variant() {
assert_tokens(
&Enum::Simple { a: 42 },
&[
Token::StructVariant { name: "Enum", variant: "Simple", len: 1 },
Token::Str("a"),
Token::I32(42),
Token::StructVariantEnd,
]
);
}
#[test]
fn flatten_variant() {
assert_tokens(
&Enum::Flatten { flatten: (), a: 42 },
&[
Token::NewtypeVariant { name: "Enum", variant: "Flatten" },
Token::Map { len: None },
Token::Str("a"),
Token::I32(42),
Token::MapEnd,
]
);
}
+18
View File
@@ -0,0 +1,18 @@
#![allow(dead_code)] // we do not read enum fields
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub enum A {
B {
c: String,
},
D {
#[serde(flatten)]
e: E,
},
}
#[derive(Deserialize)]
pub struct E {}
+50
View File
@@ -2380,6 +2380,56 @@ fn test_partially_untagged_enum_desugared() {
); );
} }
// Regression test for https://github.com/serde-rs/serde/issues/1904
#[test]
fn test_enum_tuple_and_struct_with_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Outer {
Tuple(f64, i32),
Flatten {
#[serde(flatten)]
nested: Nested,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Nested {
a: i32,
b: i32,
}
assert_tokens(
&Outer::Tuple(1.2, 3),
&[
Token::TupleVariant {
name: "Outer",
variant: "Tuple",
len: 2,
},
Token::F64(1.2),
Token::I32(3),
Token::TupleVariantEnd,
],
);
assert_tokens(
&Outer::Flatten {
nested: Nested { a: 1, b: 2 },
},
&[
Token::NewtypeVariant {
name: "Outer",
variant: "Flatten",
},
Token::Map { len: None },
Token::Str("a"),
Token::I32(1),
Token::Str("b"),
Token::I32(2),
Token::MapEnd,
],
);
}
#[test] #[test]
fn test_partially_untagged_internally_tagged_enum() { fn test_partially_untagged_internally_tagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
+2 -2
View File
@@ -162,7 +162,7 @@ fn test_cow() {
#[test] #[test]
fn test_lifetimes() { fn test_lifetimes() {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Cows<'a, 'b> { pub struct Cows<'a, 'b> {
_copied: Cow<'a, str>, _copied: Cow<'a, str>,
#[serde(borrow)] #[serde(borrow)]
@@ -178,7 +178,7 @@ fn test_lifetimes() {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct Wrap<'a, 'b> { pub struct Wrap<'a, 'b> {
#[serde(borrow = "'b")] #[serde(borrow = "'b")]
_cows: Cows<'a, 'b>, _cows: Cows<'a, 'b>,
} }
+1 -1
View File
@@ -93,7 +93,7 @@ struct StructSkipDefault {
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
#[serde(default)] #[serde(default)]
struct StructSkipDefaultGeneric<T> { pub struct StructSkipDefaultGeneric<T> {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
t: T, t: T,
} }
+79 -51
View File
@@ -4,6 +4,7 @@
#![deny(warnings)] #![deny(warnings)]
#![allow( #![allow(
confusable_idents,
unknown_lints, unknown_lints,
mixed_script_confusables, mixed_script_confusables,
clippy::derive_partial_eq_without_eq, clippy::derive_partial_eq_without_eq,
@@ -19,6 +20,7 @@
clippy::trivially_copy_pass_by_ref, clippy::trivially_copy_pass_by_ref,
clippy::type_repetition_in_bounds clippy::type_repetition_in_bounds
)] )]
#![deny(clippy::collection_is_never_read)]
use serde::de::{Deserialize, DeserializeOwned, Deserializer}; use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
@@ -287,60 +289,60 @@ fn test_gen() {
assert::<EmptyEnumVariant>(); assert::<EmptyEnumVariant>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct NonAsciiIdents { pub struct NonAsciiIdents {
σ: f64, σ: f64,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct EmptyBraced {} pub struct EmptyBraced {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct EmptyBracedDenyUnknown {} pub struct EmptyBracedDenyUnknown {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct BracedSkipAll { pub struct BracedSkipAll {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
f: u8, f: u8,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct BracedSkipAllDenyUnknown { pub struct BracedSkipAllDenyUnknown {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
f: u8, f: u8,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct EmptyTuple(); pub struct EmptyTuple();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct EmptyTupleDenyUnknown(); pub struct EmptyTupleDenyUnknown();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct TupleSkipAll(#[serde(skip_deserializing)] u8); pub struct TupleSkipAll(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8); pub struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum EmptyEnum {} pub enum EmptyEnum {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
enum EmptyEnumDenyUnknown {} pub enum EmptyEnumDenyUnknown {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum EnumSkipAll { pub enum EnumSkipAll {
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[allow(dead_code)] #[allow(dead_code)]
Variant, Variant,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum EmptyVariants { pub enum EmptyVariants {
Braced {}, Braced {},
Tuple(), Tuple(),
BracedSkip { BracedSkip {
@@ -352,7 +354,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
enum EmptyVariantsDenyUnknown { pub enum EmptyVariantsDenyUnknown {
Braced {}, Braced {},
Tuple(), Tuple(),
BracedSkip { BracedSkip {
@@ -364,21 +366,21 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct UnitDenyUnknown; pub struct UnitDenyUnknown;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct EmptyArray { pub struct EmptyArray {
empty: [X; 0], empty: [X; 0],
} }
enum Or<A, B> { pub enum Or<A, B> {
A(A), A(A),
B(B), B(B),
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(untagged, remote = "Or")] #[serde(untagged, remote = "Or")]
enum OrDef<A, B> { pub enum OrDef<A, B> {
A(A), A(A),
B(B), B(B),
} }
@@ -390,7 +392,7 @@ fn test_gen() {
struct StrDef<'a>(&'a str); struct StrDef<'a>(&'a str);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Remote<'a> { pub struct Remote<'a> {
#[serde(with = "OrDef")] #[serde(with = "OrDef")]
or: Or<u8, bool>, or: Or<u8, bool>,
#[serde(borrow, with = "StrDef")] #[serde(borrow, with = "StrDef")]
@@ -398,7 +400,7 @@ fn test_gen() {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum BorrowVariant<'a> { pub enum BorrowVariant<'a> {
#[serde(borrow, with = "StrDef")] #[serde(borrow, with = "StrDef")]
S(Str<'a>), S(Str<'a>),
} }
@@ -415,15 +417,14 @@ fn test_gen() {
// This would not work if SDef::serialize / deserialize are private. // This would not work if SDef::serialize / deserialize are private.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct RemoteVisibility { pub struct RemoteVisibility {
#[serde(with = "vis::SDef")] #[serde(with = "vis::SDef")]
s: vis::S, s: vis::S,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "Self")] #[serde(remote = "Self")]
#[allow(dead_code)] pub struct RemoteSelf;
struct RemoteSelf;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith { enum ExternallyTaggedVariantWith {
@@ -547,26 +548,45 @@ fn test_gen() {
assert::<FlattenWith>(); assert::<FlattenWith>();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] pub struct Flatten<T> {
struct FlattenDenyUnknown<T> {
#[serde(flatten)] #[serde(flatten)]
t: T, t: T,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct StaticStrStruct<'a> { #[serde(deny_unknown_fields)]
pub struct FlattenDenyUnknown<T> {
#[serde(flatten)]
t: T,
}
#[derive(Serialize, Deserialize)]
pub struct SkipDeserializing<T> {
#[serde(skip_deserializing)]
flat: T,
}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SkipDeserializingDenyUnknown<T> {
#[serde(skip_deserializing)]
flat: T,
}
#[derive(Serialize, Deserialize)]
pub struct StaticStrStruct<'a> {
a: &'a str, a: &'a str,
b: &'static str, b: &'static str,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct StaticStrTupleStruct<'a>(&'a str, &'static str); pub struct StaticStrTupleStruct<'a>(&'a str, &'static str);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct StaticStrNewtypeStruct(&'static str); pub struct StaticStrNewtypeStruct(&'static str);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> { pub enum StaticStrEnum<'a> {
Struct { a: &'a str, b: &'static str }, Struct { a: &'a str, b: &'static str },
Tuple(&'a str, &'static str), Tuple(&'a str, &'static str),
Newtype(&'static str), Newtype(&'static str),
@@ -640,6 +660,7 @@ fn test_gen() {
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[allow(dead_code)]
struct Restricted { struct Restricted {
pub(super) a: usize, pub(super) a: usize,
pub(in super::inner) b: usize, pub(in super::inner) b: usize,
@@ -649,7 +670,7 @@ fn test_gen() {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(tag = "t", content = "c")] #[serde(tag = "t", content = "c")]
enum AdjacentlyTaggedVoid {} pub enum AdjacentlyTaggedVoid {}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum SkippedVariant<T> { enum SkippedVariant<T> {
@@ -662,14 +683,13 @@ fn test_gen() {
assert::<SkippedVariant<X>>(); assert::<SkippedVariant<X>>();
#[derive(Deserialize)] #[derive(Deserialize)]
struct ImplicitlyBorrowedOption<'a> { pub struct ImplicitlyBorrowedOption<'a> {
#[allow(dead_code)]
option: std::option::Option<&'a str>, option: std::option::Option<&'a str>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum UntaggedNewtypeVariantWith { pub enum UntaggedNewtypeVariantWith {
Newtype( Newtype(
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
@@ -679,7 +699,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
struct TransparentWith { pub struct TransparentWith {
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
x: X, x: X,
@@ -701,35 +721,46 @@ fn test_gen() {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct RelObject<'a> { pub struct RelObject<'a> {
#[allow(dead_code)]
ty: &'a str, ty: &'a str,
#[allow(dead_code)]
id: String, id: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct FlattenSkipSerializing<T> { pub struct FlattenSkipSerializing<T> {
#[serde(flatten, skip_serializing)] #[serde(flatten, skip_serializing)]
#[allow(dead_code)] #[allow(dead_code)]
flat: T, flat: T,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct FlattenSkipSerializingIf<T> { pub struct FlattenSkipSerializingIf<T> {
#[serde(flatten, skip_serializing_if = "StdOption::is_none")] #[serde(flatten, skip_serializing_if = "StdOption::is_none")]
flat: StdOption<T>, flat: StdOption<T>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct FlattenSkipDeserializing<T> { pub struct FlattenSkipDeserializing<T> {
#[serde(flatten, skip_deserializing)] #[serde(flatten, skip_deserializing)]
flat: T, flat: T,
} }
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum Inner<T> {
Builder {
s: T,
#[serde(flatten)]
o: T,
},
Default {
s: T,
},
}
// https://github.com/serde-rs/serde/issues/1804 // https://github.com/serde-rs/serde/issues/1804
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum Message { pub enum Message {
#[serde(skip)] #[serde(skip)]
#[allow(dead_code)] #[allow(dead_code)]
String(String), String(String),
@@ -748,8 +779,7 @@ fn test_gen() {
macro_rules! deriving { macro_rules! deriving {
($field:ty) => { ($field:ty) => {
#[derive(Deserialize)] #[derive(Deserialize)]
struct MacroRules<'a> { pub struct MacroRules<'a> {
#[allow(dead_code)]
field: $field, field: $field,
} }
}; };
@@ -764,22 +794,20 @@ fn test_gen() {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> { pub struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")] #[serde(borrow = "'a")]
#[allow(dead_code)] pub f: mac!(Cow<'a, str>),
f: mac!(Cow<'a, str>),
} }
#[derive(Serialize)] #[derive(Serialize)]
#[allow(dead_code)] pub struct Struct {
struct Struct {
#[serde(serialize_with = "vec_first_element")] #[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>, pub vec: Vec<Self>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(bound(deserialize = "[&'de str; N]: Copy"))] #[serde(bound(deserialize = "[&'de str; N]: Copy"))]
struct GenericUnitStruct<const N: usize>; pub struct GenericUnitStruct<const N: usize>;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -866,7 +894,7 @@ where
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "tag")] #[serde(tag = "tag")]
enum InternallyTagged { pub enum InternallyTagged {
#[serde(deserialize_with = "deserialize_generic")] #[serde(deserialize_with = "deserialize_generic")]
Unit, Unit,
+15
View File
@@ -7,14 +7,17 @@ mod remote {
pub struct PrimitivePriv(u8); pub struct PrimitivePriv(u8);
#[allow(dead_code)]
pub struct PrimitivePub(pub u8); pub struct PrimitivePub(pub u8);
pub struct NewtypePriv(Unit); pub struct NewtypePriv(Unit);
#[allow(dead_code)]
pub struct NewtypePub(pub Unit); pub struct NewtypePub(pub Unit);
pub struct TuplePriv(u8, Unit); pub struct TuplePriv(u8, Unit);
#[allow(dead_code)]
pub struct TuplePub(pub u8, pub Unit); pub struct TuplePub(pub u8, pub Unit);
pub struct StructPriv { pub struct StructPriv {
@@ -22,6 +25,7 @@ mod remote {
b: Unit, b: Unit,
} }
#[allow(dead_code)]
pub struct StructPub { pub struct StructPub {
pub a: u8, pub a: u8,
pub b: Unit, pub b: Unit,
@@ -86,12 +90,14 @@ mod remote {
} }
} }
#[allow(dead_code)]
pub enum EnumGeneric<T> { pub enum EnumGeneric<T> {
Variant(T), Variant(T),
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[allow(dead_code)]
struct Test { struct Test {
#[serde(with = "UnitDef")] #[serde(with = "UnitDef")]
unit: remote::Unit, unit: remote::Unit,
@@ -132,6 +138,7 @@ struct Test {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::Unit")] #[serde(remote = "remote::Unit")]
#[allow(dead_code)]
struct UnitDef; struct UnitDef;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -140,6 +147,7 @@ struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePub")] #[serde(remote = "remote::PrimitivePub")]
#[allow(dead_code)]
struct PrimitivePubDef(u8); struct PrimitivePubDef(u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -148,6 +156,7 @@ struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitD
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePub")] #[serde(remote = "remote::NewtypePub")]
#[allow(dead_code)]
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit); struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -159,6 +168,7 @@ struct TuplePrivDef(
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePub")] #[serde(remote = "remote::TuplePub")]
#[allow(dead_code)]
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit); struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@@ -174,6 +184,7 @@ struct StructPrivDef {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")] #[serde(remote = "remote::StructPub")]
#[allow(dead_code)]
struct StructPubDef { struct StructPubDef {
a: u8, a: u8,
@@ -190,17 +201,20 @@ struct StructGenericWithGetterDef<T> {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructGeneric<u8>")] #[serde(remote = "remote::StructGeneric<u8>")]
#[allow(dead_code)]
struct StructConcrete { struct StructConcrete {
value: u8, value: u8,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "remote::EnumGeneric<u8>")] #[serde(remote = "remote::EnumGeneric<u8>")]
#[allow(dead_code)]
enum EnumConcrete { enum EnumConcrete {
Variant(u8), Variant(u8),
} }
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)]
enum ErrorKind { enum ErrorKind {
NotFound, NotFound,
PermissionDenied, PermissionDenied,
@@ -211,6 +225,7 @@ enum ErrorKind {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "ErrorKind")] #[serde(remote = "ErrorKind")]
#[non_exhaustive] #[non_exhaustive]
#[allow(dead_code)]
enum ErrorKindDef { enum ErrorKindDef {
NotFound, NotFound,
PermissionDenied, PermissionDenied,
+2 -2
View File
@@ -41,7 +41,7 @@ fn test_self() {
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct Tuple( pub struct Tuple(
Box<Self>, Box<Self>,
Box<<Self as Trait>::Assoc>, Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC], [(); Self::ASSOC],
@@ -60,7 +60,7 @@ fn test_self() {
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
enum Enum { pub enum Enum {
Struct { Struct {
_f1: Box<Self>, _f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>, _f2: Box<<Self as Trait>::Assoc>,