Compare commits

...

118 Commits

Author SHA1 Message Date
David Tolnay 30752ac4ff Release 1.0.209 2024-08-23 20:29:05 -07:00
David Tolnay b84e6ca4f5 Improve wording of PR 2805 comments 2024-08-23 20:28:11 -07:00
David Tolnay 87a2fb0f1a Wrap comments from PR 2805 to 80 columns 2024-08-23 20:25:16 -07:00
David Tolnay 9eaf7b9824 Merge pull request #2805 from Mingun/untagged-tests
Fix deserialization of empty structs and tuples in untagged enums
2024-08-23 20:25:07 -07:00
Mingun 7bde100237 Replace MapRefDeserializer with value::MapDeserializer
Although they are slightly different, this difference is irrelevant:
- MapDeserializer has a specialization for deserialize_seq and deserialize_tuple, but
  only MapRefDeserializer::deserialize_any is used by the code which is almost the same
- MapDeserializer checks that map was consumed after visit_map, but MapRefDeserializer
  does not. Actually, each derived implementation consumes map and each manual implementation
  also should consume it

Also, MapDeserializer already used when value deserialized from ContentRefDeserializer
directly and MapRefDeserializer was only used to deserialize Struct variants of enums.
There are no reasons why the behavior should be different in those two cases
2024-08-24 04:52:26 +05:00
Mingun da7fc795ee Fix deserialization of empty struct variant in untagged enums
SeqRefDeserializer::deserialize_any has a special condition for empty sequence, which
emits visit_unit. That condition assumes that type would be able to deserialized from
unit, but:
1) struct variants was never able to deserialize from it (they expect only visit_map or visit_seq)
2) tuple variants even with zero fields expect visit_seq only. The suggestion to accept visit_unit
   instead was rejected in #2520

Fixes (2):
    newtype_enum::tuple0
    newtype_enum::empty_struct_from_seq
2024-08-24 04:52:26 +05:00
Mingun 4c5fec1363 Test special cases that reaches SeqRefDeserializer::deserialize_any len==0 condition
failures (2):
    newtype_enum::empty_struct_from_seq
    newtype_enum::tuple0
2024-08-24 04:52:25 +05:00
Mingun 6588b0ad37 Cover Content::Seq case in VariantRefDeserializer::struct_variant 2024-08-24 04:52:25 +05:00
Mingun 0093f74cfe Split test newtype_enum into four tests for each variant
(review this commit with "ignore whitespace changes" option on)
2024-08-24 04:52:25 +05:00
Mingun 171c6da57a Complete coverage of ContentRefDeserializer::deserialize_newtype_struct 2024-08-24 04:52:25 +05:00
Mingun 2dddc7796d Cover ContentRefDeserializer::deserialize_option 2024-08-24 04:52:25 +05:00
Mingun 8514f4119a Remove unnecessary generics 2024-08-24 04:52:24 +05:00
Mingun 98fb7d94aa Move all untagged enum tests (except flatten) into a dedicated module
Moved and renamed:
From test_annotations
- test_expecting_message_untagged_tagged_enum                  => expecting_message
- flatten::enum_::untagged::straitforward                      => contains_flatten

From test_macros
- test_untagged_newtype_struct                                 => newtype_struct
- test_untagged_enum                                           => complex
- test_untagged_enum_with_flattened_integer_key                => contains_flatten_with_integer_key
- test_enum_in_untagged_enum                                   => newtype_enum
- test_untagged_bytes                                          => string_and_bytes
- test_untagged_newtype_variant_containing_unit_struct_not_map => newtype_unit_and_empty_map
2024-08-24 04:52:22 +05:00
David Tolnay 31ca16d9bc Merge pull request #2804 from Mingun/adjacently-tagged-tests
Consolidate and add new tests of adjacently tagged enums
2024-08-23 14:12:41 -07:00
Mingun 9f72ce695e Struct: add tests for deserialization from sequence
(review this commit with "ignore whitespace changes" option on)
2024-08-16 22:51:42 +05:00
Mingun c383e4f953 Tuple: add tests for deserialization from sequence
(review this commit with "ignore whitespace changes" option on)
2024-08-16 22:51:16 +05:00
Mingun a94d8750fb Newtype: move up the test with tag only 2024-08-16 22:51:13 +05:00
Mingun b0d651be40 Newtype: add tests for deserialization from sequence
(review this commit with "ignore whitespace changes" option on)
2024-08-16 22:51:13 +05:00
Mingun d5a9c11b5c No need to test integer and byte array field names, they already tested for Unit case
There is no difference what variant is deserialized so we can test only one kind of variant
2024-08-16 22:51:10 +05:00
Mingun 6bfe1c435a Unit: add tests for deserialization from bytes tag and content fields 2024-08-16 22:43:15 +05:00
Mingun a02da49b87 Unit: add tests for deserialization from integer tag and content fields 2024-08-16 22:43:15 +05:00
Mingun 29dc6c3367 Unit: add tests for deserialization from sequence
(review this commit with "ignore whitespace changes" option on)
2024-08-16 22:38:02 +05:00
Mingun a7f0bab078 Document fields in internal structs used to deserialize adjacently tagged enums 2024-08-16 21:39:55 +05:00
Mingun 3dc6829303 Integrate bytes test into struct_ test
`newtype` test also integrates test with `Bytes` tag, so be like

Removed the first assert_tokens because it is the same as the first assert in the merged method
2024-08-16 21:39:53 +05:00
Mingun 42e63ff942 Reuse AdjacentlyTagged enum in bytes test
Change 0i32 to 1u8 so the test can be merged with the previous in the next commit
2024-08-16 21:38:23 +05:00
Mingun df07751e6f Group newtype and newtype_with_newtype tests 2024-08-16 21:36:56 +05:00
Mingun 5445f1741b Reuse AdjacentlyTagged enum in newtype_with_newtype test 2024-08-16 21:36:56 +05:00
Mingun 9d0f811221 Remove unnecessary generic 2024-08-16 21:36:56 +05:00
Mingun 36b9a859c4 Test deserialization of the serialized unit format for adjacently tagged enum 2024-08-16 21:36:55 +05:00
Mingun 59628d1712 Create only one value for all checks 2024-08-16 21:36:55 +05:00
Mingun bee7470715 Split test test_adjacently_tagged_enum into four tests for each variant
(review this commit with "ignore whitespace changes" option on)
2024-08-16 21:36:55 +05:00
Mingun 5a359e10f4 Group Newtype variant checks in test_adjacently_tagged_enum together 2024-08-16 21:36:55 +05:00
Mingun 5e37ade519 Move all adjacently tagged enum tests (except flatten) into a dedicated module
Moved and renamed:
From test_annotatons
- test_adjacently_tagged_enum_bytes               => bytes
- flatten::enum_::adjacently_tagged::straitforward=> struct_with_flatten
- test_expecting_message_adjacently_tagged_enum   => expecting_message
- test_partially_untagged_adjacently_tagged_enum  => partially_untagged

From test_macros
- test_adjacently_tagged_newtype_struct           => newtype_with_newtype
- test_adjacently_tagged_enum
- test_adjacently_tagged_enum_deny_unknown_fields => deny_unknown_fields
2024-08-16 21:36:52 +05:00
David Tolnay 1a9ffdbd0c Merge pull request #2788 from Mingun/internally-tagged-enum-tests
Consolidate and add new tests of internally tagged enums
2024-08-15 14:42:28 -07:00
Mingun 2adb0e99b0 Add additional checks for unit and newtype_unit tests
- check that unit variant can be deserialized from a map
- check that newtype variant with unit can be deserialized from a struct
2024-08-15 23:39:14 +05:00
Mingun 71ed1f2f12 Add tests for special and general cases for internally tagged enums
Special case is the tag field first (so the enum variant are known after reading the first entry from map).
General case is the tag field not the first (so we need to buffer entries until we found an entry with tag)
2024-08-15 23:39:13 +05:00
Mingun 47954502af Add tests with borrowed strings for the tag field name and tag value 2024-08-15 23:39:13 +05:00
Mingun 4987fd15f7 Convert newtype_enum and struct_enum tests into modules
Separate testing each variant kind of enum (unit, newtype, tuple, struct) results
in more specific information if that checks fail

(review this commit with "ignore whitespace changes" option on)
2024-08-15 23:39:12 +05:00
Mingun 8bfe0d0ac0 Move and rename tests:
- newtype_variant_containing_unit                   -> newtype_unit
- newtype_variant_containing_unit_struct            -> newtype_unit_struct
- newtype_variant_containing_externally_tagged_enum -> newtype_enum
- struct_variant_containing_unit_variant            -> struct_enum
2024-08-15 23:39:12 +05:00
Mingun 7c0e6bd18f Reuse type in struct_variant_containing_unit_variant 2024-08-15 23:39:11 +05:00
Mingun 41b9c33c2b Reuse type in newtype_variant_containing_externally_tagged_enum 2024-08-15 23:39:11 +05:00
Mingun 28a775db22 Share externally tagged enum Enum between all tests and reuse in struct_variant_containing_unit_variant 2024-08-15 23:39:10 +05:00
Mingun e999600f8f Rename externally tagged enum Inner to Enum 2024-08-15 23:39:10 +05:00
Mingun d3492d8d36 Reuse type in newtype_variant_containing_unit_struct 2024-08-15 23:39:09 +05:00
Mingun 48de0c51b0 Share unit struct Unit between all tests 2024-08-15 23:39:09 +05:00
Mingun 93bda5f1dc Rename unit struct to a generic name: Info->Unit 2024-08-15 23:39:09 +05:00
Mingun 2d75ef6b30 Reuse type in newtype_variant_containing_unit 2024-08-15 23:39:07 +05:00
Mingun f97160f715 Reuse type in unit_variant_with_unknown_fields and add test for sequence 2024-08-15 23:39:06 +05:00
Mingun eb59c776ca Use name "tag" to refer to tag field 2024-08-15 23:39:06 +05:00
Mingun 9128201c78 Use the same order of derives 2024-08-15 23:39:05 +05:00
Mingun 2cbfd37072 Move all other internally tagged enum tests into a dedicated file
Moved all except flattened tests:
- test_internally_tagged_enum_with_skipped_conflict    => with_skipped_conflict
- test_internally_tagged_enum_new_type_with_unit       => newtype_variant_containing_unit
- test_internally_tagged_unit_enum_with_unknown_fields => unit_variant_with_unknown_fields
- test_expecting_message_internally_tagged_enum        => expecting_message
- flatten::enum_::internally_tagged::straightforward   => containing_flatten
2024-08-15 23:39:05 +05:00
Mingun 0939214c51 Move internally tagged enum tests into a dedicated file
Ctrl+X, Ctrl+V
2024-08-15 23:34:01 +05:00
Mingun 8c60f5aea7 Reorder enum variants and tests to canonical order (Unit, Newtype, Tuple, Struct) 2024-08-15 23:34:00 +05:00
Mingun da0ed4021d Give meaningful names to enum variants 2024-08-15 23:34:00 +05:00
Mingun 99f905403b Move all internally tagged enum tests of test_macros into a dedicated module
Moved:
- test_internally_tagged_enum_with_untagged_variant             => untagged_variant
- test_internally_tagged_bytes                                  => string_and_bytes mod
- test_internally_tagged_struct_variant_containing_unit_variant => struct_variant_containing_unit_variant
- test_internally_tagged_borrow                                 => borrow
- test_enum_in_internally_tagged_enum                           => newtype_variant_containing_externally_tagged_enum
- test_internally_tagged_newtype_variant_containing_unit_struct => newtype_variant_containing_unit_struct

(review this commit with "ignore whitespace changes" option on)
2024-08-15 23:34:00 +05:00
Mingun aa0654332d Convert test_internally_tagged_enum into module
(review this commit with "ignore whitespace changes" option on)
2024-08-15 23:33:59 +05:00
David Tolnay af376c22c3 Merge pull request #2803 from jonhoo/mv-flatten-tests
Group flatten tests
2024-08-15 10:53:49 -07:00
Jon Gjengset 477eb7b70e Group flatten tests 2024-08-15 18:28:49 +02:00
David Tolnay 026e91a68c Release 1.0.208 2024-08-15 08:41:27 -07:00
David Tolnay bfbedac919 Merge pull request #2802 from jonhoo/flatten-unit-struct
Support (de-)serializing flattened unit struct
2024-08-15 08:40:11 -07:00
Jon Gjengset 4036ff88ed Support (de-)serializing flattened unit struct
Fixes #2801.
2024-08-15 15:50:54 +02:00
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
David Tolnay 18dcae0a77 Release 1.0.204 2024-07-06 13:38:01 -07:00
David Tolnay 58c307f9cc Alphabetize list of rustc-check-cfg 2024-07-06 13:37:24 -07:00
David Tolnay 8cc4809414 Merge pull request #2769 from dtolnay/onunimpl
Add ui test of unsatisfied serde trait bound
2024-07-06 13:33:50 -07:00
David Tolnay 1179158def Update ui test with diagnostic::on_unimplemented from PR 2767 2024-07-06 13:29:51 -07:00
David Tolnay 91aa40e749 Add ui test of unsatisfied serde trait bound 2024-07-06 13:29:50 -07:00
David Tolnay 595019e979 Cut test_suite from workspace members in old toolchain CI jobs
The test suite's dependencies cannot be resolved by an old toolchain.

    error: failed to select a version for the requirement `toml = "^0.8"`
    candidate versions found which didn't match: 0.5.11, 0.5.10, 0.5.9, ...
    location searched: crates.io index
    required by package `trybuild v1.0.97`
        ... which satisfies dependency `trybuild = "^1.0.97"` of package `serde_test_suite v0.0.0`
2024-07-06 13:25:55 -07:00
David Tolnay b0d7917f88 Pull in trybuild 'following types implement trait' fix 2024-07-06 13:13:32 -07:00
David Tolnay 8e6637a1e4 Merge pull request #2767 from weiznich/feature/diagnostic_on_unimplemented
Use the `#[diagnostic::on_unimplemented]` attribute when possible
2024-07-06 10:29:08 -07:00
Georg Semmler 694fe05953 Use the #[diagnostic::on_unimplemented] attribute when possible
This change enables the `#[diagnostic::on_unimplemented]` attribute for
the `Serialize` and `Deserialize` trait to point the user to the
relevant derives and point out that they might want to check crates
features for external types by adding the relevant hints an note.
2024-07-02 16:39:06 +02:00
David Tolnay f3dfd2a237 Suppress dead code warning in test of unit struct remote derive
error: struct `RemoteSelf` is never constructed
       --> test_suite/tests/test_gen.rs:425:12
        |
    425 |     struct RemoteSelf;
        |            ^^^^^^^^^^
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`
2024-06-26 19:41:25 -07:00
David Tolnay 9e6158e9e6 Nightly no longer requires error_in_core feature
warning: the feature `error_in_core` has been stable since 1.81.0-nightly and no longer requires an attribute to enable
       --> serde/src/lib.rs:108:43
        |
    108 | #![cfg_attr(feature = "unstable", feature(error_in_core, never_type))]
        |                                           ^^^^^^^^^^^^^
        |
        = note: `#[warn(stable_features)]` on by default
2024-06-10 09:47:24 -07:00
David Tolnay d577c4a2ce Merge pull request #2754 from bm-w/master
Fix missing close paren in crates-io.md
2024-06-06 21:32:01 -07:00
Bastiaan Marinus van de Weerd fee0b82a40 Fix missing close paren in crates-io.md 2024-06-06 23:19:04 -04:00
David Tolnay 7aafa26314 Fill in ignore reasons in all #[ignore] attributes 2024-06-01 22:13:43 -07:00
David Tolnay d5bc546ca5 Release 1.0.203 2024-05-25 10:43:27 -07:00
David Tolnay 45ae217728 Merge pull request #2747 from dtolnay/variadic
Document tuple impls as fake variadic
2024-05-25 10:15:58 -07:00
David Tolnay b7b97dda73 Unindent implementation inside tuple_impl_body macro 2024-05-25 10:11:45 -07:00
David Tolnay 5d3c563d46 Document tuple impls as fake variadic 2024-05-25 10:11:04 -07:00
David Tolnay 376185458b Merge pull request #2745 from dtolnay/docsrs
Rely on docs.rs to define --cfg=docsrs by default
2024-05-18 21:25:44 -07:00
David Tolnay a8f14840ab Rely on docs.rs to define --cfg=docsrs by default 2024-05-18 21:16:37 -07:00
David Tolnay 9e32a40b1c Release 1.0.202 2024-05-15 00:42:49 -07:00
David Tolnay 87f635e54d Release serde_derive_internals 0.29.1 2024-05-15 00:35:14 -07:00
David Tolnay d4b2dfbde2 Merge pull request #2743 from dtolnay/renameallrules
Provide public access to RenameAllRules in serde_derive_internals
2024-05-15 00:34:38 -07:00
David Tolnay f6ab0bc56f Provide public access to RenameAllRules in serde_derive_internals 2024-05-15 00:30:55 -07:00
David Tolnay 48cc2a6327 Replace use of a syn From impl
The From impls may be going away in the next version of syn.
2024-05-14 23:02:28 -07:00
David Tolnay 3202a6858a Skip rerunning build script on library code changes 2024-05-08 21:59:41 -07:00
David Tolnay b4f1bc16ff Release 1.0.201 2024-05-07 17:02:11 -07:00
David Tolnay 029ab46f71 Merge pull request #2737 from dtolnay/checkcfg
Resolve unexpected_cfgs warning
2024-05-07 17:01:43 -07:00
David Tolnay 220ca0ca9d Resolve unexpected_cfgs warning
warning: unexpected `cfg` condition name: `serde_build_from_git`
      --> serde_derive_internals/lib.rs:45:12
       |
    45 | #[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
       |            ^^^^^^^^^^^^^^^^^^^^
       |
       = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
       = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(serde_build_from_git)");` to the top of the `build.rs`
       = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
       = note: `#[warn(unexpected_cfgs)]` on by default

    warning: unexpected `cfg` condition name: `serde_build_from_git`
      --> serde_derive_internals/lib.rs:46:16
       |
    46 | #[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
       |                ^^^^^^^^^^^^^^^^^^^^
       |
       = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(serde_build_from_git)");` to the top of the `build.rs`
       = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition value: `deserialize_in_place`
       --> serde_derive_internals/src/attr.rs:276:11
        |
    276 |     #[cfg(feature = "deserialize_in_place")]
        |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the condition
        |
        = note: no expected values for `feature`
        = help: consider adding `deserialize_in_place` as a feature in `Cargo.toml`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
        --> serde_derive_internals/src/attr.rs:1797:31
         |
    1797 |         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
         |                               ^^^^^^^^^^
         |
         = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
         = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive_internals/src/receiver.rs:110:35
        |
    110 |             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                   ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive_internals/src/receiver.rs:181:47
        |
    181 |                         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                               ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive_internals/src/receiver.rs:210:35
        |
    210 |             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                   ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive_internals/src/receiver.rs:231:43
        |
    231 |                     #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                           ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
      --> serde_derive/src/lib.rs:62:23
       |
    62 | #![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
       |                       ^^^^^^^^^^
       |
       = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
       = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
       = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
       = note: `#[warn(unexpected_cfgs)]` on by default

    warning: unexpected `cfg` condition name: `exhaustive`
        --> serde_derive/src/internals/attr.rs:1797:31
         |
    1797 |         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
         |                               ^^^^^^^^^^
         |
         = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
         = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/internals/receiver.rs:110:35
        |
    110 |             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                   ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/internals/receiver.rs:181:47
        |
    181 |                         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                               ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/internals/receiver.rs:210:35
        |
    210 |             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                   ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/internals/receiver.rs:231:43
        |
    231 |                     #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                           ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/bound.rs:147:39
        |
    147 |                 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                       ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/bound.rs:199:51
        |
    199 | ...                   #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                             ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `exhaustive`
       --> serde_derive/src/bound.rs:228:39
        |
    228 |                 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                       ^^^^^^^^^^
        |
        = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(exhaustive)");` to the top of the `build.rs`
        = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration

    warning: unexpected `cfg` condition name: `systemtime_checked_add`
        --> test_suite/tests/test_de_error.rs:1527:7
         |
    1527 | #[cfg(systemtime_checked_add)]
         |       ^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
         = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(systemtime_checked_add)");` to the top of the `build.rs`
         = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
         = note: `#[warn(unexpected_cfgs)]` on by default
2024-05-07 16:55:01 -07:00
David Tolnay 20306f493a Fix cfg on test_systemtime_overflow 2024-05-07 16:53:53 -07:00
42 changed files with 4267 additions and 2832 deletions
+3
View File
@@ -84,6 +84,7 @@ jobs:
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
- run: sed -i '/"test_suite"/d' Cargo.toml
- run: cd serde && cargo build --features rc
- run: cd serde && cargo build --no-default-features
- run: cd serde && cargo build
@@ -95,6 +96,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.56.0
- run: sed -i '/"test_suite"/d' Cargo.toml
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
@@ -106,6 +108,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.36.0
- run: sed -i '/"test_suite"/d' Cargo.toml
- run: cd serde && cargo build --no-default-features --features alloc
minimal:
+2 -2
View File
@@ -46,8 +46,8 @@ fn main() {
Serde is one of the most widely used Rust libraries so any place that Rustaceans
congregate will be able to help you out. For chat, consider trying the
[#rust-questions] or [#rust-beginners] channels of the unofficial community
Discord (invite: <https://discord.gg/rust-lang-community>, the [#rust-usage] or
[#beginners] channels of the official Rust Project Discord (invite:
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage]
or [#beginners] channels of the official Rust Project Discord (invite:
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.200"
version = "1.0.209"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -29,7 +29,7 @@ features = ["derive", "rc"]
[package.metadata.docs.rs]
features = ["derive", "rc", "unstable"]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
rustdoc-args = ["--generate-link-to-definition"]
# This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's
# version in lockstep with serde's, even if someone depends on the two crates
@@ -37,7 +37,7 @@ rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
# is compatible with exactly one serde release because the generated code
# involves nonpublic APIs which are not bound by semver.
[target.'cfg(any())'.dependencies]
serde_derive = { version = "=1.0.200", path = "../serde_derive" }
serde_derive = { version = "=1.0.209", path = "../serde_derive" }
### FEATURES #################################################################
+21
View File
@@ -13,6 +13,21 @@ fn main() {
None => return,
};
if minor >= 77 {
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
println!("cargo:rustc-check-cfg=cfg(no_core_try_from)");
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
println!("cargo:rustc-check-cfg=cfg(no_float_copysign)");
println!("cargo:rustc-check-cfg=cfg(no_num_nonzero_signed)");
println!("cargo:rustc-check-cfg=cfg(no_relaxed_trait_bounds)");
println!("cargo:rustc-check-cfg=cfg(no_serde_derive)");
println!("cargo:rustc-check-cfg=cfg(no_std_atomic)");
println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)");
println!("cargo:rustc-check-cfg=cfg(no_systemtime_checked_add)");
println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)");
}
let target = env::var("TARGET").unwrap();
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
@@ -70,6 +85,12 @@ fn main() {
if minor < 74 {
println!("cargo:rustc-cfg=no_core_num_saturating");
}
// Support for the `#[diagnostic]` tool attribute namespace
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
if minor < 78 {
println!("cargo:rustc-cfg=no_diagnostic_namespace");
}
}
fn rustc_minor_version() -> Option<u32> {
+127 -106
View File
@@ -39,7 +39,7 @@ impl<'de> Deserialize<'de> for () {
}
#[cfg(feature = "unstable")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "unstable")))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
impl<'de> Deserialize<'de> for ! {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
@@ -695,7 +695,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de> Deserialize<'de> for String {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -839,7 +839,7 @@ impl<'de> Visitor<'de> for CStringVisitor {
}
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de> Deserialize<'de> for CString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -868,7 +868,7 @@ macro_rules! forwarded_impl {
forwarded_impl! {
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
(), Box<CStr>, CString::into_boxed_c_str
}
@@ -1086,7 +1086,7 @@ fn nop_reserve<T>(_seq: T, _n: usize) {}
seq_impl!(
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BinaryHeap<T: Ord>,
seq,
BinaryHeap::clear,
@@ -1097,7 +1097,7 @@ seq_impl!(
seq_impl!(
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BTreeSet<T: Eq + Ord>,
seq,
BTreeSet::clear,
@@ -1108,7 +1108,7 @@ seq_impl!(
seq_impl!(
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
LinkedList<T>,
seq,
LinkedList::clear,
@@ -1119,7 +1119,7 @@ seq_impl!(
seq_impl!(
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
HashSet<T: Eq + Hash, S: BuildHasher + Default>,
seq,
HashSet::clear,
@@ -1130,7 +1130,7 @@ seq_impl!(
seq_impl!(
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
VecDeque<T>,
seq,
VecDeque::clear,
@@ -1142,7 +1142,7 @@ seq_impl!(
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, T> Deserialize<'de> for Vec<T>
where
T: Deserialize<'de>,
@@ -1393,82 +1393,103 @@ array_impls! {
macro_rules! tuple_impls {
($($len:tt => ($($n:tt $name:ident)+))+) => {
$(
impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct TupleVisitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match tri!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData })
}
#[inline]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+));
impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
$(
if tri!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() {
return Err(Error::invalid_length($n, &self));
}
)+
Ok(())
}
}
deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place))
}
#[cfg_attr(docsrs, doc(hidden))]
impl<'de, $($name),+> Deserialize<'de> for ($($name,)+)
where
$($name: Deserialize<'de>,)+
{
tuple_impl_body!($len => ($($n $name)+));
}
)+
}
};
}
macro_rules! tuple_impl_body {
($len:tt => ($($n:tt $name:ident)+)) => {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct TupleVisitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match tri!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData })
}
#[inline]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+));
impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
$(
if tri!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() {
return Err(Error::invalid_length($n, &self));
}
)+
Ok(())
}
}
deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place))
}
};
}
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(
docsrs,
doc = "This trait is implemented for tuples up to 16 items long."
)]
impl<'de, T> Deserialize<'de> for (T,)
where
T: Deserialize<'de>,
{
tuple_impl_body!(1 => (0 T));
}
tuple_impls! {
1 => (0 T0)
2 => (0 T0 1 T1)
3 => (0 T0 1 T1 2 T2)
4 => (0 T0 1 T1 2 T2 3 T3)
@@ -1546,7 +1567,7 @@ macro_rules! map_impl {
map_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BTreeMap<K: Ord, V>,
map,
BTreeMap::new(),
@@ -1554,7 +1575,7 @@ map_impl! {
map_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map,
HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default()),
@@ -1696,7 +1717,7 @@ macro_rules! deserialize_enum {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de> Deserialize<'de> for net::IpAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1717,13 +1738,13 @@ impl<'de> Deserialize<'de> for net::IpAddr {
parse_ip_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::Ipv4Addr, "IPv4 address", 4
}
parse_ip_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::Ipv6Addr, "IPv6 address", 16
}
@@ -1750,7 +1771,7 @@ macro_rules! parse_socket_impl {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de> Deserialize<'de> for net::SocketAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1771,14 +1792,14 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
parse_socket_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::SocketAddrV4, "IPv4 socket address",
|(ip, port)| net::SocketAddrV4::new(ip, port),
}
parse_socket_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::SocketAddrV6, "IPv6 socket address",
|(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0),
}
@@ -1814,7 +1835,7 @@ impl<'a> Visitor<'a> for PathVisitor {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de: 'a, 'a> Deserialize<'de> for &'a Path {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1869,7 +1890,7 @@ impl<'de> Visitor<'de> for PathBufVisitor {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de> Deserialize<'de> for PathBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1881,7 +1902,7 @@ impl<'de> Deserialize<'de> for PathBuf {
forwarded_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
(), Box<Path>, PathBuf::into_boxed_path
}
@@ -1943,7 +1964,7 @@ impl<'de> Visitor<'de> for OsStringVisitor {
}
#[cfg(all(feature = "std", any(unix, windows)))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
impl<'de> Deserialize<'de> for OsString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1957,30 +1978,30 @@ impl<'de> Deserialize<'de> for OsString {
forwarded_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
(T), Box<T>, Box::new
}
forwarded_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
(T), Box<[T]>, Vec::into_boxed_slice
}
forwarded_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
(), Box<str>, String::into_boxed_str
}
forwarded_impl! {
#[cfg(all(feature = "std", any(unix, windows)))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
(), Box<OsStr>, OsString::into_boxed_os_str
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T>
where
T: ?Sized + ToOwned,
@@ -2003,7 +2024,7 @@ where
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(
doc_cfg,
docsrs,
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
)]
impl<'de, T> Deserialize<'de> for RcWeak<T>
@@ -2025,7 +2046,7 @@ where
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(
doc_cfg,
docsrs,
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
)]
impl<'de, T> Deserialize<'de> for ArcWeak<T>
@@ -2073,7 +2094,7 @@ box_forwarded_impl! {
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
Rc
}
@@ -2086,7 +2107,7 @@ box_forwarded_impl! {
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
Arc
}
@@ -2110,13 +2131,13 @@ forwarded_impl! {
forwarded_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
(T), Mutex<T>, Mutex::new
}
forwarded_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
(T), RwLock<T>, RwLock::new
}
@@ -2271,7 +2292,7 @@ impl<'de> Deserialize<'de> for Duration {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de> Deserialize<'de> for SystemTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -3107,7 +3128,7 @@ macro_rules! atomic_impl {
($($ty:ident $size:expr)*) => {
$(
#[cfg(any(no_target_has_atomic, target_has_atomic = $size))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
+9 -2
View File
@@ -532,6 +532,13 @@ impl<'a> Display for Expected + 'a {
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
///
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
note = "for local types consider adding `#[derive(serde::Deserialize)]` to your `{Self}` type",
note = "for types from other crates check whether the crate offers a `serde` feature flag",
)
)]
pub trait Deserialize<'de>: Sized {
/// Deserialize this value from the given Serde deserializer.
///
@@ -1525,7 +1532,7 @@ pub trait Visitor<'de>: Sized {
/// `String`.
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
@@ -1584,7 +1591,7 @@ pub trait Visitor<'de>: Sized {
/// The default implementation forwards to `visit_bytes` and then drops the
/// `Vec<u8>`.
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: Error,
+12 -12
View File
@@ -112,7 +112,7 @@ impl Debug for Error {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for Error {
fn description(&self) -> &str {
&self.err
@@ -185,14 +185,14 @@ impl<E> Debug for UnitDeserializer<E> {
/// A deserializer that cannot be instantiated.
#[cfg(feature = "unstable")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "unstable")))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
pub struct NeverDeserializer<E> {
never: !,
marker: PhantomData<E>,
}
#[cfg(feature = "unstable")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "unstable")))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
impl<'de, E> IntoDeserializer<'de, E> for !
where
E: de::Error,
@@ -565,7 +565,7 @@ impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
/// A deserializer holding a `String`.
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub struct StringDeserializer<E> {
value: String,
marker: PhantomData<E>,
@@ -582,7 +582,7 @@ impl<E> Clone for StringDeserializer<E> {
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, E> IntoDeserializer<'de, E> for String
where
E: de::Error,
@@ -670,7 +670,7 @@ impl<E> Debug for StringDeserializer<E> {
/// A deserializer holding a `Cow<str>`.
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub struct CowStrDeserializer<'a, E> {
value: Cow<'a, str>,
marker: PhantomData<E>,
@@ -687,7 +687,7 @@ impl<'a, E> Clone for CowStrDeserializer<'a, E> {
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
where
E: de::Error,
@@ -1006,7 +1006,7 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T>
where
T: IntoDeserializer<'de, E>,
@@ -1020,7 +1020,7 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T>
where
T: IntoDeserializer<'de, E> + Eq + Ord,
@@ -1034,7 +1034,7 @@ where
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
where
T: IntoDeserializer<'de, E> + Eq + Hash,
@@ -1421,7 +1421,7 @@ impl Expected for ExpectedInMap {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V>
where
K: IntoDeserializer<'de, E> + Eq + Ord,
@@ -1436,7 +1436,7 @@ where
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
where
K: IntoDeserializer<'de, E> + Eq + Hash,
+5 -4
View File
@@ -95,16 +95,17 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.200")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.209")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Show which crate feature enables conditionally compiled APIs in documentation.
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))]
#![cfg_attr(docsrs, allow(internal_features))]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
// https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(error_in_core, never_type))]
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
// Ignored clippy and clippy_pedantic lints
#![allow(
@@ -330,7 +331,7 @@ extern crate serde_derive;
/// Derive macro available if serde is built with `features = ["derive"]`.
#[cfg(feature = "serde_derive")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
pub use serde_derive::{Deserialize, Serialize};
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
+58 -162
View File
@@ -904,7 +904,9 @@ mod content {
/// Not public API.
pub struct TagOrContentFieldVisitor {
/// Name of the tag field of the adjacently tagged enum
pub tag: &'static str,
/// Name of the content field of the adjacently tagged enum
pub content: &'static str,
}
@@ -979,7 +981,9 @@ mod content {
/// Not public API.
pub struct TagContentOtherFieldVisitor {
/// Name of the tag field of the adjacently tagged enum
pub tag: &'static str,
/// Name of the content field of the adjacently tagged enum
pub content: &'static str,
}
@@ -1894,10 +1898,19 @@ mod content {
where
V: Visitor<'de>,
{
// Covered by tests/test_enum_untagged.rs
// with_optional_field::*
match *self.content {
Content::None => visitor.visit_none(),
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
Content::Unit => visitor.visit_unit(),
// This case is to support data formats which do not encode an
// indication whether a value is optional. An example of such a
// format is JSON, and a counterexample is RON. When requesting
// `deserialize_any` in JSON, the data format never performs
// `Visitor::visit_some` but we still must be able to
// deserialize the resulting Content into data structures with
// optional fields.
_ => visitor.visit_some(self),
}
}
@@ -1927,10 +1940,21 @@ mod content {
where
V: Visitor<'de>,
{
// Covered by tests/test_enum_untagged.rs
// newtype_struct
match *self.content {
Content::Newtype(ref v) => {
visitor.visit_newtype_struct(ContentRefDeserializer::new(v))
}
// This case is to support data formats that encode newtype
// structs and their underlying data the same, with no
// indication whether a newtype wrapper was present. For example
// JSON does this, while RON does not. In RON a newtype's name
// is included in the serialized representation and it knows to
// call `Visitor::visit_newtype_struct` from `deserialize_any`.
// JSON's `deserialize_any` never calls `visit_newtype_struct`
// but in this code we still must be able to deserialize the
// resulting Content into newtypes.
_ => visitor.visit_newtype_struct(self),
}
}
@@ -2135,6 +2159,10 @@ mod content {
fn unit_variant(self) -> Result<(), E> {
match self.value {
Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)),
// Covered by tests/test_annotations.rs
// test_partially_untagged_adjacently_tagged_enum
// Covered by tests/test_enum_untagged.rs
// newtype_enum::unit
None => Ok(()),
}
}
@@ -2144,6 +2172,11 @@ mod content {
T: de::DeserializeSeed<'de>,
{
match self.value {
// Covered by tests/test_annotations.rs
// test_partially_untagged_enum_desugared
// test_partially_untagged_enum_generic
// Covered by tests/test_enum_untagged.rs
// newtype_enum::newtype
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
@@ -2157,9 +2190,13 @@ mod content {
V: de::Visitor<'de>,
{
match self.value {
Some(Content::Seq(v)) => {
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
}
// Covered by tests/test_annotations.rs
// test_partially_untagged_enum
// test_partially_untagged_enum_desugared
// Covered by tests/test_enum_untagged.rs
// newtype_enum::tuple0
// newtype_enum::tuple2
Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor),
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"tuple variant",
@@ -2180,12 +2217,13 @@ mod content {
V: de::Visitor<'de>,
{
match self.value {
Some(Content::Map(v)) => {
de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
}
Some(Content::Seq(v)) => {
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
}
// Covered by tests/test_enum_untagged.rs
// newtype_enum::struct_from_map
Some(Content::Map(v)) => visit_content_map_ref(v, visitor),
// Covered by tests/test_enum_untagged.rs
// newtype_enum::struct_from_seq
// newtype_enum::empty_struct_from_seq
Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor),
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"struct variant",
@@ -2198,158 +2236,6 @@ mod content {
}
}
struct SeqRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
iter: <&'a [Content<'de>] as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
fn new(slice: &'a [Content<'de>]) -> Self {
SeqRefDeserializer {
iter: slice.iter(),
err: PhantomData,
}
}
}
impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
type Error = E;
#[inline]
fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let len = self.iter.len();
if len == 0 {
visitor.visit_unit()
} else {
let ret = tri!(visitor.visit_seq(&mut self));
let remaining = self.iter.len();
if remaining == 0 {
Ok(ret)
} else {
Err(de::Error::invalid_length(len, &"fewer elements in array"))
}
}
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
impl<'de, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
type Error = E;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => seed
.deserialize(ContentRefDeserializer::new(value))
.map(Some),
None => Ok(None),
}
}
fn size_hint(&self) -> Option<usize> {
size_hint::from_bounds(&self.iter)
}
}
struct MapRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter,
value: Option<&'a Content<'de>>,
err: PhantomData<E>,
}
impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self {
MapRefDeserializer {
iter: map.iter(),
value: None,
err: PhantomData,
}
}
}
impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => Err(de::Error::custom("value is missing")),
}
}
fn size_hint(&self) -> Option<usize> {
size_hint::from_bounds(&self.iter)
}
}
impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
type Error = E;
#[inline]
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_map(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E>
where
E: de::Error,
@@ -2710,6 +2596,17 @@ where
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
@@ -2734,7 +2631,6 @@ where
deserialize_string()
deserialize_bytes()
deserialize_byte_buf()
deserialize_unit_struct(&'static str)
deserialize_seq()
deserialize_tuple(usize)
deserialize_tuple_struct(&'static str, usize)
+2 -7
View File
@@ -51,8 +51,6 @@ enum Unsupported {
String,
ByteArray,
Optional,
#[cfg(any(feature = "std", feature = "alloc"))]
UnitStruct,
Sequence,
Tuple,
TupleStruct,
@@ -69,8 +67,6 @@ impl Display for Unsupported {
Unsupported::String => formatter.write_str("a string"),
Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"),
#[cfg(any(feature = "std", feature = "alloc"))]
Unsupported::UnitStruct => formatter.write_str("unit struct"),
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
@@ -1092,7 +1088,7 @@ where
}
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
Err(Self::bad_type(Unsupported::UnitStruct))
Ok(())
}
fn serialize_unit_variant(
@@ -1125,8 +1121,7 @@ where
where
T: ?Sized + Serialize,
{
tri!(self.0.serialize_key(variant));
self.0.serialize_value(value)
self.0.serialize_entry(variant, value)
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+63 -45
View File
@@ -48,7 +48,7 @@ impl Serialize for str {
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl Serialize for String {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -71,7 +71,7 @@ impl<'a> Serialize for fmt::Arguments<'a> {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", not(no_core_cstr)))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for CStr {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -83,7 +83,7 @@ impl Serialize for CStr {
}
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
impl Serialize for CString {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -232,37 +232,37 @@ macro_rules! seq_impl {
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BinaryHeap<T: Ord>
}
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BTreeSet<T: Ord>
}
seq_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
HashSet<T: Eq + Hash, H: BuildHasher>
}
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
LinkedList<T>
}
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
Vec<T>
}
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
VecDeque<T>
}
@@ -371,7 +371,7 @@ impl Serialize for () {
}
#[cfg(feature = "unstable")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "unstable")))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
impl Serialize for ! {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
@@ -386,28 +386,46 @@ impl Serialize for ! {
macro_rules! tuple_impls {
($($len:expr => ($($n:tt $name:ident)+))+) => {
$(
#[cfg_attr(docsrs, doc(hidden))]
impl<$($name),+> Serialize for ($($name,)+)
where
$($name: Serialize,)+
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tuple = tri!(serializer.serialize_tuple($len));
$(
tri!(tuple.serialize_element(&self.$n));
)+
tuple.end()
}
tuple_impl_body!($len => ($($n)+));
}
)+
}
};
}
macro_rules! tuple_impl_body {
($len:expr => ($($n:tt)+)) => {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tuple = tri!(serializer.serialize_tuple($len));
$(
tri!(tuple.serialize_element(&self.$n));
)+
tuple.end()
}
};
}
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(
docsrs,
doc = "This trait is implemented for tuples up to 16 items long."
)]
impl<T> Serialize for (T,)
where
T: Serialize,
{
tuple_impl_body!(1 => (0));
}
tuple_impls! {
1 => (0 T0)
2 => (0 T0 1 T1)
3 => (0 T0 1 T1 2 T2)
4 => (0 T0 1 T1 2 T2 3 T3)
@@ -476,13 +494,13 @@ macro_rules! map_impl {
map_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BTreeMap<K: Ord, V>
}
map_impl! {
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
HashMap<K: Eq + Hash, V, H: BuildHasher>
}
@@ -516,7 +534,7 @@ deref_impl! {
deref_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
<T> Serialize for Box<T> where T: ?Sized + Serialize
}
@@ -530,7 +548,7 @@ deref_impl! {
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
<T> Serialize for Rc<T> where T: ?Sized + Serialize
}
@@ -544,13 +562,13 @@ deref_impl! {
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
<T> Serialize for Arc<T> where T: ?Sized + Serialize
}
deref_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "std", feature = "alloc"))))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
<'a, T> Serialize for Cow<'a, T> where T: ?Sized + Serialize + ToOwned
}
@@ -561,7 +579,7 @@ deref_impl! {
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(
doc_cfg,
docsrs,
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
)]
impl<T> Serialize for RcWeak<T>
@@ -581,7 +599,7 @@ where
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
#[cfg_attr(
doc_cfg,
docsrs,
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
)]
impl<T> Serialize for ArcWeak<T>
@@ -660,7 +678,7 @@ where
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<T> Serialize for Mutex<T>
where
T: ?Sized + Serialize,
@@ -677,7 +695,7 @@ where
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<T> Serialize for RwLock<T>
where
T: ?Sized + Serialize,
@@ -731,7 +749,7 @@ impl Serialize for Duration {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for SystemTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -776,7 +794,7 @@ macro_rules! serialize_display_bounded_length {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -847,7 +865,7 @@ fn test_format_u8() {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::Ipv4Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -872,7 +890,7 @@ impl Serialize for net::Ipv4Addr {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::Ipv6Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -889,7 +907,7 @@ impl Serialize for net::Ipv6Addr {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::SocketAddr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -914,7 +932,7 @@ impl Serialize for net::SocketAddr {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::SocketAddrV4 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -931,7 +949,7 @@ impl Serialize for net::SocketAddrV4 {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for net::SocketAddrV6 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -953,7 +971,7 @@ impl Serialize for net::SocketAddrV6 {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for Path {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -967,7 +985,7 @@ impl Serialize for Path {
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Serialize for PathBuf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -978,7 +996,7 @@ impl Serialize for PathBuf {
}
#[cfg(all(feature = "std", any(unix, windows)))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
impl Serialize for OsStr {
#[cfg(unix)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -1001,7 +1019,7 @@ impl Serialize for OsStr {
}
#[cfg(all(feature = "std", any(unix, windows)))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
impl Serialize for OsString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -1060,7 +1078,7 @@ macro_rules! atomic_impl {
($($ty:ident $size:expr)*) => {
$(
#[cfg(any(no_target_has_atomic, target_has_atomic = $size))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
impl Serialize for $ty {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
+7
View File
@@ -215,6 +215,13 @@ declare_error_trait!(Error: Sized + Debug + Display);
/// [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
/// [`serde_derive`]: https://crates.io/crates/serde_derive
/// [derive section of the manual]: https://serde.rs/derive.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
note = "for local types consider adding `#[derive(serde::Serialize)]` to your `{Self}` type",
note = "for types from other crates check whether the crate offers a `serde` feature flag",
)
)]
pub trait Serialize {
/// Serialize this value into the given Serde serializer.
///
+2 -1
View File
@@ -1,11 +1,12 @@
[package]
name = "serde_derive"
version = "1.0.200"
version = "1.0.209"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html"
edition = "2015"
exclude = ["build.rs"]
homepage = "https://serde.rs"
keywords = ["serde", "serialization", "no_std", "derive"]
license = "MIT OR Apache-2.0"
+8
View File
@@ -0,0 +1,8 @@
fn main() {
// Warning: build.rs is not published to crates.io.
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-cfg=check_cfg");
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
println!("cargo:rustc-check-cfg=cfg(exhaustive)");
}
+52 -28
View File
@@ -461,7 +461,10 @@ fn deserialize_tuple(
cattrs: &attr::Container,
form: TupleForm,
) -> Fragment {
assert!(!cattrs.has_flatten());
assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields
.iter()
@@ -579,7 +582,10 @@ fn deserialize_tuple_in_place(
fields: &[Field],
cattrs: &attr::Container,
) -> Fragment {
assert!(!cattrs.has_flatten());
assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields
.iter()
@@ -958,13 +964,15 @@ fn deserialize_struct(
)
})
.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
// structs that only have a map representation.
let visit_seq = match form {
StructForm::Untagged(..) => None,
_ if cattrs.has_flatten() => None,
_ if has_flatten => None,
_ => {
let mut_seq = if field_names_idents.is_empty() {
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 {
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 {
type Value = #this_type #ty_generics;
@@ -1005,7 +1019,7 @@ fn deserialize_struct(
_ => None,
};
let fields_stmt = if cattrs.has_flatten() {
let fields_stmt = if has_flatten {
None
} else {
let field_names = field_names_idents
@@ -1025,7 +1039,7 @@ fn deserialize_struct(
}
};
let dispatch = match form {
StructForm::Struct if cattrs.has_flatten() => quote! {
StructForm::Struct if has_flatten => quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
},
StructForm::Struct => {
@@ -1034,7 +1048,7 @@ fn deserialize_struct(
_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)
},
StructForm::ExternallyTagged(_) => quote! {
@@ -1091,7 +1105,7 @@ fn deserialize_struct_in_place(
) -> Option<Fragment> {
// for now we do not support in_place deserialization for structs that
// are represented as map.
if cattrs.has_flatten() {
if has_flatten(fields) {
return None;
}
@@ -1116,7 +1130,7 @@ fn deserialize_struct_in_place(
})
.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() {
quote!(_)
@@ -1210,10 +1224,7 @@ fn deserialize_homogeneous_enum(
}
}
fn prepare_enum_variant_enum(
variants: &[Variant],
cattrs: &attr::Container,
) -> (TokenStream, Stmts) {
fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
let mut deserialized_variants = variants
.iter()
.enumerate()
@@ -1247,7 +1258,7 @@ fn prepare_enum_variant_enum(
let variant_visitor = Stmts(deserialize_generated_identifier(
&variant_names_idents,
cattrs,
false, // variant identifiers do not depend on the presence of flatten fields
true,
None,
fallthrough,
@@ -1270,7 +1281,7 @@ fn deserialize_externally_tagged_enum(
let expecting = format!("enum {}", params.type_name());
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
let variant_arms = variants
@@ -1355,7 +1366,7 @@ fn deserialize_internally_tagged_enum(
cattrs: &attr::Container,
tag: &str,
) -> 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
let variant_arms = variants
@@ -1409,7 +1420,7 @@ fn deserialize_adjacently_tagged_enum(
split_with_de_lifetime(params);
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
.iter()
@@ -1985,7 +1996,7 @@ fn deserialize_untagged_newtype_variant(
fn deserialize_generated_identifier(
fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container,
has_flatten: bool,
is_variant: bool,
ignore_variant: Option<TokenStream>,
fallthrough: Option<TokenStream>,
@@ -1999,11 +2010,11 @@ fn deserialize_generated_identifier(
is_variant,
fallthrough,
None,
!is_variant && cattrs.has_flatten(),
!is_variant && has_flatten,
None,
));
let lifetime = if !is_variant && cattrs.has_flatten() {
let lifetime = if !is_variant && has_flatten {
Some(quote!(<'de>))
} else {
None
@@ -2043,8 +2054,9 @@ fn deserialize_generated_identifier(
fn deserialize_field_identifier(
fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container,
has_flatten: bool,
) -> 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 fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value)));
(Some(ignore_variant), Some(fallthrough))
@@ -2058,7 +2070,7 @@ fn deserialize_field_identifier(
Stmts(deserialize_generated_identifier(
fields,
cattrs,
has_flatten,
false,
ignore_variant,
fallthrough,
@@ -2460,6 +2472,7 @@ fn deserialize_map(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
has_flatten: bool,
) -> Fragment {
// Create the field names for the fields.
let fields_names: Vec<_> = fields
@@ -2480,7 +2493,7 @@ fn deserialize_map(
});
// Collect contents for flatten fields into a buffer
let let_collect = if cattrs.has_flatten() {
let let_collect = if has_flatten {
Some(quote! {
let mut __collect = _serde::__private::Vec::<_serde::__private::Option<(
_serde::__private::de::Content,
@@ -2532,7 +2545,7 @@ fn deserialize_map(
});
// Visit ignored values to consume them
let ignored_arm = if cattrs.has_flatten() {
let ignored_arm = if has_flatten {
Some(quote! {
__Field::__other(__name) => {
__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! {
if let _serde::__private::Some(_serde::__private::Some((__key, _))) =
__collect.into_iter().filter(_serde::__private::Option::is_some).next()
@@ -2678,7 +2691,10 @@ fn deserialize_map_in_place(
fields: &[Field],
cattrs: &attr::Container,
) -> 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.
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);
#[cfg(feature = "deserialize_in_place")]
struct InPlaceImplGenerics<'a>(&'a Parameters);
+1 -12
View File
@@ -63,7 +63,7 @@ impl<'a> Container<'a> {
item: &'a syn::DeriveInput,
derive: Derive,
) -> 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 {
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 {
Data::Enum(variants) => {
for variant in variants {
variant.attrs.rename_by_rules(attrs.rename_all_rules());
for field in &mut variant.fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rules(
variant
.attrs
@@ -97,18 +93,11 @@ impl<'a> Container<'a> {
}
Data::Struct(_, fields) => {
for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rules(attrs.rename_all_rules());
}
}
}
if has_flatten {
attrs.mark_has_flatten();
}
let mut item = Container {
ident: item.ident.clone(),
attrs,
+2 -12
View File
@@ -185,8 +185,8 @@ impl Name {
#[derive(Copy, Clone)]
pub struct RenameAllRules {
serialize: RenameRule,
deserialize: RenameRule,
pub serialize: RenameRule,
pub deserialize: RenameRule,
}
impl RenameAllRules {
@@ -216,7 +216,6 @@ pub struct Container {
type_into: Option<syn::Type>,
remote: Option<syn::Path>,
identifier: Identifier,
has_flatten: bool,
serde_path: Option<syn::Path>,
is_packed: bool,
/// Error message generated when type can't be deserialized
@@ -587,7 +586,6 @@ impl Container {
type_into: type_into.get(),
remote: remote.get(),
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
has_flatten: false,
serde_path: serde_path.get(),
is_packed,
expecting: expecting.get(),
@@ -655,14 +653,6 @@ impl Container {
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> {
self.serde_path.as_ref()
}
+1 -1
View File
@@ -84,7 +84,7 @@ impl ReplaceReceiver<'_> {
self.visit_type_mut_impl(ty);
return;
};
*ty = self.self_ty(span).into();
*ty = Type::Path(self.self_ty(span));
}
// `Self::Assoc` -> `<Receiver>::Assoc`
+2 -1
View File
@@ -13,7 +13,8 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.200")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.209")]
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
+12 -21
View File
@@ -289,9 +289,18 @@ fn serialize_tuple_struct(
}
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)
} else {
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 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! {
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
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.29.0"
version = "0.29.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals"
+8
View File
@@ -1,9 +1,17 @@
use std::path::Path;
fn main() {
// Warning: build.rs is not published to crates.io.
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/mod.rs");
println!("cargo:rustc-cfg=check_cfg");
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
println!("cargo:rustc-check-cfg=cfg(exhaustive)");
println!("cargo:rustc-check-cfg=cfg(serde_build_from_git)");
println!("cargo:rustc-check-cfg=cfg(feature, values(\"deserialize_in_place\"))");
// Sometimes on Windows the git checkout does not correctly wire up the
// symlink from serde_derive_internals/src to serde_derive/src/internals.
// When this happens we'll just build based on relative paths within the git
+2 -1
View File
@@ -1,4 +1,5 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.29.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.29.1")]
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
// Ignored clippy lints
#![allow(
clippy::cognitive_complexity,
+1 -1
View File
@@ -18,4 +18,4 @@ rustversion = "1.0"
serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = "1.0.176"
trybuild = { version = "1.0.66", features = ["diff"] }
trybuild = { version = "1.0.97", features = ["diff"] }
+5 -5
View File
@@ -23,21 +23,21 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Unit;
pub struct Unit;
#[derive(Serialize, Deserialize)]
struct Newtype(u8);
pub struct Newtype(u8);
#[derive(Serialize, Deserialize)]
struct Tuple(u8, u8);
pub struct Tuple(u8, u8);
#[derive(Serialize, Deserialize)]
struct Struct {
pub struct Struct {
f: u8,
}
#[derive(Serialize, Deserialize)]
enum Enum {
pub enum Enum {
Unit,
Newtype(u8),
Tuple(u8, u8),
+3 -3
View File
@@ -1,6 +1,6 @@
#[cfg_attr(target_os = "emscripten", ignore)]
#[rustversion::attr(not(nightly), ignore)]
#[cfg_attr(miri, ignore)]
#[cfg_attr(target_os = "emscripten", ignore = "disabled on Emscripten")]
#[rustversion::attr(not(nightly), ignore = "requires nightly")]
#[cfg_attr(miri, ignore = "incompatible with miri")]
#[allow(unused_attributes)]
#[test]
fn ui() {
+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 {}
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -162,7 +162,7 @@ fn test_cow() {
#[test]
fn test_lifetimes() {
#[derive(Deserialize)]
struct Cows<'a, 'b> {
pub struct Cows<'a, 'b> {
_copied: Cow<'a, str>,
#[serde(borrow)]
@@ -178,7 +178,7 @@ fn test_lifetimes() {
}
#[derive(Deserialize)]
struct Wrap<'a, 'b> {
pub struct Wrap<'a, 'b> {
#[serde(borrow = "'b")]
_cows: Cows<'a, 'b>,
}
+1 -1
View File
@@ -93,7 +93,7 @@ struct StructSkipDefault {
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructSkipDefaultGeneric<T> {
pub struct StructSkipDefaultGeneric<T> {
#[serde(skip_deserializing)]
t: T,
}
-1
View File
@@ -1524,7 +1524,6 @@ fn test_systemtime_overflow_struct() {
);
}
#[cfg(systemtime_checked_add)]
#[test]
fn test_systemtime_overflow() {
assert_de_tokens_error::<SystemTime>(
@@ -0,0 +1,799 @@
#![deny(trivial_numeric_casts)]
#![allow(
clippy::derive_partial_eq_without_eq,
clippy::enum_variant_names,
clippy::redundant_field_names,
clippy::too_many_lines
)]
use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "t", content = "c")]
enum AdjacentlyTagged<T> {
Unit,
Newtype(T),
Tuple(u8, u8),
Struct { f: u8 },
}
mod unit {
use super::*;
#[test]
fn map_str_tag_only() {
// Map: tag only
assert_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
// Map: tag only and incorrect hint for number of elements
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
}
#[test]
fn map_int_tag_only() {
// Map: tag (as number) only
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::U16(0),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
}
#[test]
fn map_bytes_tag_only() {
// Map: tag only
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::Bytes(b"t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
// Map: tag only
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::BorrowedBytes(b"t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
}
#[test]
fn map_str_tag_content() {
// Map: tag + content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::Str("c"),
Token::Unit,
Token::StructEnd,
],
);
// Map: content + tag
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::Unit,
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
// Map: tag + content + excess fields (f, g, h)
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("f"),
Token::Unit,
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::Str("g"),
Token::Unit,
Token::Str("c"),
Token::Unit,
Token::Str("h"),
Token::Unit,
Token::StructEnd,
],
);
}
#[test]
fn map_int_tag_content() {
// Map: tag (as number) + content (as number)
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::U8(0),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::U8(1),
Token::Unit,
Token::StructEnd,
],
);
// Map: content (as number) + tag (as number)
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::U64(1),
Token::Unit,
Token::U64(0),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
}
#[test]
fn map_bytes_tag_content() {
// Map: tag + content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::BorrowedBytes(b"t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::BorrowedBytes(b"c"),
Token::Unit,
Token::StructEnd,
],
);
// Map: content + tag
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Bytes(b"c"),
Token::Unit,
Token::Bytes(b"t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::StructEnd,
],
);
}
#[test]
fn seq_tag_content() {
// Seq: tag and content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Seq { len: Some(2) },
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::Unit,
Token::SeqEnd,
],
);
// Seq: tag (as string) and content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Seq { len: None },
Token::Str("Unit"), // tag
Token::Unit, // content
Token::SeqEnd,
],
);
// Seq: tag (as borrowed string) and content
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Seq { len: None },
Token::BorrowedStr("Unit"), // tag
Token::Unit, // content
Token::SeqEnd,
],
);
}
}
mod newtype {
use super::*;
#[test]
fn map_tag_only() {
// optional newtype with no content field
assert_de_tokens(
&AdjacentlyTagged::Newtype::<Option<u8>>(None),
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Newtype",
},
Token::StructEnd,
],
);
}
#[test]
fn map_tag_content() {
let value = AdjacentlyTagged::Newtype::<u8>(1);
// Map: tag + content
assert_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Newtype",
},
Token::Str("c"),
Token::U8(1),
Token::StructEnd,
],
);
// Map: content + tag
assert_de_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::U8(1),
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Newtype",
},
Token::StructEnd,
],
);
}
#[test]
fn seq() {
let value = AdjacentlyTagged::Newtype::<u8>(1);
// Seq: tag and content
assert_de_tokens(
&value,
&[
Token::Seq { len: Some(2) },
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Newtype",
},
Token::U8(1),
Token::SeqEnd,
],
);
// Seq: tag (as string) and content
assert_de_tokens(
&value,
&[
Token::Seq { len: None },
Token::Str("Newtype"), // tag
Token::U8(1), // content
Token::SeqEnd,
],
);
// Seq: tag (as borrowed string) and content
assert_de_tokens(
&value,
&[
Token::Seq { len: None },
Token::BorrowedStr("Newtype"), // tag
Token::U8(1), // content
Token::SeqEnd,
],
);
}
}
#[test]
fn newtype_with_newtype() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct NewtypeStruct(u32);
assert_de_tokens(
&AdjacentlyTagged::Newtype(NewtypeStruct(5)),
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::NewtypeStruct {
name: "NewtypeStruct",
},
Token::U32(5),
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Newtype",
},
Token::StructEnd,
],
);
}
mod tuple {
use super::*;
#[test]
fn map() {
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
// Map: tag + content
assert_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Tuple",
},
Token::Str("c"),
Token::Tuple { len: 2 },
Token::U8(1),
Token::U8(1),
Token::TupleEnd,
Token::StructEnd,
],
);
// Map: content + tag
assert_de_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::Tuple { len: 2 },
Token::U8(1),
Token::U8(1),
Token::TupleEnd,
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Tuple",
},
Token::StructEnd,
],
);
}
#[test]
fn seq() {
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
// Seq: tag + content
assert_de_tokens(
&value,
&[
Token::Seq { len: Some(2) },
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Tuple",
},
Token::Tuple { len: 2 },
Token::U8(1),
Token::U8(1),
Token::TupleEnd,
Token::SeqEnd,
],
);
}
}
mod struct_ {
use super::*;
#[test]
fn map() {
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
// Map: tag + content
assert_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Struct",
},
Token::Str("c"),
Token::Struct {
name: "Struct",
len: 1,
},
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::StructEnd,
],
);
// Map: content + tag
assert_de_tokens(
&value,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::Struct {
name: "Struct",
len: 1,
},
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Struct",
},
Token::StructEnd,
],
);
}
#[test]
fn seq() {
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
// Seq: tag + content
assert_de_tokens(
&value,
&[
Token::Seq { len: Some(2) },
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Struct",
},
Token::Struct {
name: "Struct",
len: 1,
},
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::SeqEnd,
],
);
}
}
#[test]
fn struct_with_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "Data",
variant: "A",
},
Token::Str("c"),
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
Token::StructEnd,
],
);
}
#[test]
fn expecting_message() {
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
#[serde(expecting = "something strange...")]
enum Enum {
AdjacentlyTagged,
}
assert_de_tokens_error::<Enum>(
&[Token::Str("AdjacentlyTagged")],
r#"invalid type: string "AdjacentlyTagged", expected something strange..."#,
);
assert_de_tokens_error::<Enum>(
&[Token::Map { len: None }, Token::Unit],
r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#,
);
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
assert_de_tokens_error::<Enum>(
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
"invalid type: unit value, expected variant of enum Enum",
);
}
#[test]
fn partially_untagged() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A(u32),
B,
#[serde(untagged)]
Var(u32),
}
let data = Data::A(7);
assert_de_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::U32(7),
Token::MapEnd,
],
);
let data = Data::Var(42);
assert_de_tokens(&data, &[Token::U32(42)]);
// TODO test error output
}
#[test]
fn deny_unknown_fields() {
#[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "t", content = "c", deny_unknown_fields)]
enum AdjacentlyTagged {
Unit,
}
assert_de_tokens(
&AdjacentlyTagged::Unit,
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::Str("c"),
Token::Unit,
Token::StructEnd,
],
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("t"),
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::Str("c"),
Token::Unit,
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Str("c"),
Token::Unit,
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::U64(0), // tag field
Token::UnitVariant {
name: "AdjacentlyTagged",
variant: "Unit",
},
Token::U64(3),
],
r#"invalid value: integer `3`, expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Bytes(b"c"),
Token::Unit,
Token::Bytes(b"h"),
],
r#"invalid value: byte array, expected "t" or "c""#,
);
}
File diff suppressed because it is too large Load Diff
+583
View File
@@ -0,0 +1,583 @@
#![deny(trivial_numeric_casts)]
#![allow(
clippy::derive_partial_eq_without_eq,
clippy::enum_variant_names,
clippy::redundant_field_names,
clippy::too_many_lines
)]
mod bytes;
use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
use std::collections::BTreeMap;
#[test]
fn complex() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Untagged {
A { a: u8 },
B { b: u8 },
C,
D(u8),
E(String),
F(u8, u8),
}
assert_tokens(
&Untagged::A { a: 1 },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("a"),
Token::U8(1),
Token::StructEnd,
],
);
assert_tokens(
&Untagged::B { b: 2 },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("b"),
Token::U8(2),
Token::StructEnd,
],
);
// Serializes to unit, deserializes from either depending on format's
// preference.
assert_tokens(&Untagged::C, &[Token::Unit]);
assert_de_tokens(&Untagged::C, &[Token::None]);
assert_tokens(&Untagged::D(4), &[Token::U8(4)]);
assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]);
assert_tokens(
&Untagged::F(1, 2),
&[
Token::Tuple { len: 2 },
Token::U8(1),
Token::U8(2),
Token::TupleEnd,
],
);
assert_de_tokens_error::<Untagged>(
&[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd],
"data did not match any variant of untagged enum Untagged",
);
assert_de_tokens_error::<Untagged>(
&[
Token::Tuple { len: 3 },
Token::U8(1),
Token::U8(2),
Token::U8(3),
Token::TupleEnd,
],
"data did not match any variant of untagged enum Untagged",
);
}
#[test]
fn newtype_unit_and_empty_map() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Unit;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Message {
Unit(Unit),
Map(BTreeMap<String, String>),
}
assert_tokens(
&Message::Map(BTreeMap::new()),
&[Token::Map { len: Some(0) }, Token::MapEnd],
);
}
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_newtype_struct
#[test]
fn newtype_struct() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct NewtypeStruct(u32);
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum E {
Newtype(NewtypeStruct),
Null,
}
let value = E::Newtype(NewtypeStruct(5));
// Content::Newtype case
assert_tokens(
&value,
&[
Token::NewtypeStruct {
name: "NewtypeStruct",
},
Token::U32(5),
],
);
// _ case
assert_de_tokens(&value, &[Token::U32(5)]);
}
mod newtype_enum {
use super::*;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Outer {
Inner(Inner),
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Inner {
Unit,
Newtype(u8),
Tuple0(),
Tuple2(u8, u8),
Struct { f: u8 },
EmptyStruct {},
}
// Reaches crate::private::de::content::VariantRefDeserializer::unit_variant
#[test]
fn unit() {
assert_tokens(
&Outer::Inner(Inner::Unit),
&[Token::UnitVariant {
name: "Inner",
variant: "Unit",
}],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::newtype_variant_seed
#[test]
fn newtype() {
assert_tokens(
&Outer::Inner(Inner::Newtype(1)),
&[
Token::NewtypeVariant {
name: "Inner",
variant: "Newtype",
},
Token::U8(1),
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
#[test]
fn tuple0() {
assert_tokens(
&Outer::Inner(Inner::Tuple0()),
&[
Token::TupleVariant {
name: "Inner",
variant: "Tuple0",
len: 0,
},
Token::TupleVariantEnd,
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
#[test]
fn tuple2() {
assert_tokens(
&Outer::Inner(Inner::Tuple2(1, 1)),
&[
Token::TupleVariant {
name: "Inner",
variant: "Tuple2",
len: 2,
},
Token::U8(1),
Token::U8(1),
Token::TupleVariantEnd,
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
// Content::Map case
#[test]
fn struct_from_map() {
assert_tokens(
&Outer::Inner(Inner::Struct { f: 1 }),
&[
Token::StructVariant {
name: "Inner",
variant: "Struct",
len: 1,
},
Token::Str("f"),
Token::U8(1),
Token::StructVariantEnd,
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
// Content::Seq case
#[test]
fn struct_from_seq() {
assert_de_tokens(
&Outer::Inner(Inner::Struct { f: 1 }),
&[
Token::Map { len: Some(1) },
// tag
Token::Str("Struct"),
// content
Token::Seq { len: Some(1) },
Token::U8(1),
Token::SeqEnd,
Token::MapEnd,
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
// Content::Map case
// Special case - empty map
#[test]
fn empty_struct_from_map() {
assert_de_tokens(
&Outer::Inner(Inner::EmptyStruct {}),
&[
Token::Map { len: Some(1) },
// tag
Token::Str("EmptyStruct"),
// content
Token::Map { len: Some(0) },
Token::MapEnd,
Token::MapEnd,
],
);
}
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
// Content::Seq case
// Special case - empty seq
#[test]
fn empty_struct_from_seq() {
assert_de_tokens(
&Outer::Inner(Inner::EmptyStruct {}),
&[
Token::Map { len: Some(1) },
// tag
Token::Str("EmptyStruct"),
// content
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::MapEnd,
],
);
}
}
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_option
mod with_optional_field {
use super::*;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Enum {
Struct { optional: Option<u32> },
Null,
}
#[test]
fn some() {
assert_tokens(
&Enum::Struct { optional: Some(42) },
&[
Token::Struct {
name: "Enum",
len: 1,
},
Token::Str("optional"),
Token::Some,
Token::U32(42),
Token::StructEnd,
],
);
}
#[test]
fn some_without_marker() {
assert_de_tokens(
&Enum::Struct { optional: Some(42) },
&[
Token::Struct {
name: "Enum",
len: 1,
},
Token::Str("optional"),
Token::U32(42),
Token::StructEnd,
],
);
}
#[test]
fn none() {
assert_tokens(
&Enum::Struct { optional: None },
&[
Token::Struct {
name: "Enum",
len: 1,
},
Token::Str("optional"),
Token::None,
Token::StructEnd,
],
);
}
#[test]
fn unit() {
assert_de_tokens(
&Enum::Struct { optional: None },
&[
Token::Map { len: None },
Token::Str("optional"),
Token::Unit,
Token::MapEnd,
],
);
}
}
#[test]
fn string_and_bytes() {
#[derive(Debug, PartialEq, Deserialize)]
#[serde(untagged)]
enum Untagged {
String {
string: String,
},
Bytes {
#[serde(with = "bytes")]
bytes: Vec<u8>,
},
}
assert_de_tokens(
&Untagged::String {
string: "\0".to_owned(),
},
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String {
string: "\0".to_owned(),
},
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String {
string: "\0".to_owned(),
},
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String {
string: "\0".to_owned(),
},
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Seq { len: Some(1) },
Token::U8(0),
Token::SeqEnd,
Token::StructEnd,
],
);
}
#[test]
fn contains_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum Data {
A {
a: i32,
#[serde(flatten)]
flat: Flat,
},
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Flat {
b: i32,
}
let data = Data::A {
a: 0,
flat: Flat { b: 0 },
};
assert_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::Str("b"),
Token::I32(0),
Token::MapEnd,
],
);
}
#[test]
fn contains_flatten_with_integer_key() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Untagged {
Variant {
#[serde(flatten)]
map: BTreeMap<u64, String>,
},
}
assert_tokens(
&Untagged::Variant {
map: {
let mut map = BTreeMap::new();
map.insert(100, "BTreeMap".to_owned());
map
},
},
&[
Token::Map { len: None },
Token::U64(100),
Token::Str("BTreeMap"),
Token::MapEnd,
],
);
}
#[test]
fn expecting_message() {
#[derive(Deserialize)]
#[serde(untagged)]
#[serde(expecting = "something strange...")]
enum Enum {
Untagged,
}
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], "something strange...");
}
+79 -50
View File
@@ -4,6 +4,7 @@
#![deny(warnings)]
#![allow(
confusable_idents,
unknown_lints,
mixed_script_confusables,
clippy::derive_partial_eq_without_eq,
@@ -19,6 +20,7 @@
clippy::trivially_copy_pass_by_ref,
clippy::type_repetition_in_bounds
)]
#![deny(clippy::collection_is_never_read)]
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde::ser::{Serialize, Serializer};
@@ -287,60 +289,60 @@ fn test_gen() {
assert::<EmptyEnumVariant>();
#[derive(Serialize, Deserialize)]
struct NonAsciiIdents {
pub struct NonAsciiIdents {
σ: f64,
}
#[derive(Serialize, Deserialize)]
struct EmptyBraced {}
pub struct EmptyBraced {}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct EmptyBracedDenyUnknown {}
pub struct EmptyBracedDenyUnknown {}
#[derive(Serialize, Deserialize)]
struct BracedSkipAll {
pub struct BracedSkipAll {
#[serde(skip_deserializing)]
f: u8,
}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct BracedSkipAllDenyUnknown {
pub struct BracedSkipAllDenyUnknown {
#[serde(skip_deserializing)]
f: u8,
}
#[derive(Serialize, Deserialize)]
struct EmptyTuple();
pub struct EmptyTuple();
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct EmptyTupleDenyUnknown();
pub struct EmptyTupleDenyUnknown();
#[derive(Serialize, Deserialize)]
struct TupleSkipAll(#[serde(skip_deserializing)] u8);
pub struct TupleSkipAll(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
pub struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
#[derive(Serialize, Deserialize)]
enum EmptyEnum {}
pub enum EmptyEnum {}
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum EmptyEnumDenyUnknown {}
pub enum EmptyEnumDenyUnknown {}
#[derive(Serialize, Deserialize)]
enum EnumSkipAll {
pub enum EnumSkipAll {
#[serde(skip_deserializing)]
#[allow(dead_code)]
Variant,
}
#[derive(Serialize, Deserialize)]
enum EmptyVariants {
pub enum EmptyVariants {
Braced {},
Tuple(),
BracedSkip {
@@ -352,7 +354,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum EmptyVariantsDenyUnknown {
pub enum EmptyVariantsDenyUnknown {
Braced {},
Tuple(),
BracedSkip {
@@ -364,21 +366,21 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct UnitDenyUnknown;
pub struct UnitDenyUnknown;
#[derive(Serialize, Deserialize)]
struct EmptyArray {
pub struct EmptyArray {
empty: [X; 0],
}
enum Or<A, B> {
pub enum Or<A, B> {
A(A),
B(B),
}
#[derive(Serialize, Deserialize)]
#[serde(untagged, remote = "Or")]
enum OrDef<A, B> {
pub enum OrDef<A, B> {
A(A),
B(B),
}
@@ -390,7 +392,7 @@ fn test_gen() {
struct StrDef<'a>(&'a str);
#[derive(Serialize, Deserialize)]
struct Remote<'a> {
pub struct Remote<'a> {
#[serde(with = "OrDef")]
or: Or<u8, bool>,
#[serde(borrow, with = "StrDef")]
@@ -398,7 +400,7 @@ fn test_gen() {
}
#[derive(Serialize, Deserialize)]
enum BorrowVariant<'a> {
pub enum BorrowVariant<'a> {
#[serde(borrow, with = "StrDef")]
S(Str<'a>),
}
@@ -415,14 +417,14 @@ fn test_gen() {
// This would not work if SDef::serialize / deserialize are private.
#[derive(Serialize, Deserialize)]
struct RemoteVisibility {
pub struct RemoteVisibility {
#[serde(with = "vis::SDef")]
s: vis::S,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Self")]
struct RemoteSelf;
pub struct RemoteSelf;
#[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith {
@@ -546,26 +548,45 @@ fn test_gen() {
assert::<FlattenWith>();
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct FlattenDenyUnknown<T> {
pub struct Flatten<T> {
#[serde(flatten)]
t: T,
}
#[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,
b: &'static str,
}
#[derive(Serialize, Deserialize)]
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
pub struct StaticStrTupleStruct<'a>(&'a str, &'static str);
#[derive(Serialize, Deserialize)]
struct StaticStrNewtypeStruct(&'static str);
pub struct StaticStrNewtypeStruct(&'static str);
#[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> {
pub enum StaticStrEnum<'a> {
Struct { a: &'a str, b: &'static str },
Tuple(&'a str, &'static str),
Newtype(&'static str),
@@ -639,6 +660,7 @@ fn test_gen() {
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[allow(dead_code)]
struct Restricted {
pub(super) a: usize,
pub(in super::inner) b: usize,
@@ -648,7 +670,7 @@ fn test_gen() {
#[derive(Deserialize)]
#[serde(tag = "t", content = "c")]
enum AdjacentlyTaggedVoid {}
pub enum AdjacentlyTaggedVoid {}
#[derive(Serialize, Deserialize)]
enum SkippedVariant<T> {
@@ -661,14 +683,13 @@ fn test_gen() {
assert::<SkippedVariant<X>>();
#[derive(Deserialize)]
struct ImplicitlyBorrowedOption<'a> {
#[allow(dead_code)]
pub struct ImplicitlyBorrowedOption<'a> {
option: std::option::Option<&'a str>,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum UntaggedNewtypeVariantWith {
pub enum UntaggedNewtypeVariantWith {
Newtype(
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
@@ -678,7 +699,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct TransparentWith {
pub struct TransparentWith {
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
x: X,
@@ -700,35 +721,46 @@ fn test_gen() {
}
#[derive(Deserialize)]
struct RelObject<'a> {
#[allow(dead_code)]
pub struct RelObject<'a> {
ty: &'a str,
#[allow(dead_code)]
id: String,
}
#[derive(Serialize, Deserialize)]
struct FlattenSkipSerializing<T> {
pub struct FlattenSkipSerializing<T> {
#[serde(flatten, skip_serializing)]
#[allow(dead_code)]
flat: T,
}
#[derive(Serialize, Deserialize)]
struct FlattenSkipSerializingIf<T> {
pub struct FlattenSkipSerializingIf<T> {
#[serde(flatten, skip_serializing_if = "StdOption::is_none")]
flat: StdOption<T>,
}
#[derive(Serialize, Deserialize)]
struct FlattenSkipDeserializing<T> {
pub struct FlattenSkipDeserializing<T> {
#[serde(flatten, skip_deserializing)]
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
#[derive(Serialize, Deserialize)]
enum Message {
pub enum Message {
#[serde(skip)]
#[allow(dead_code)]
String(String),
@@ -747,8 +779,7 @@ fn test_gen() {
macro_rules! deriving {
($field:ty) => {
#[derive(Deserialize)]
struct MacroRules<'a> {
#[allow(dead_code)]
pub struct MacroRules<'a> {
field: $field,
}
};
@@ -763,22 +794,20 @@ fn test_gen() {
}
#[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> {
pub struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")]
#[allow(dead_code)]
f: mac!(Cow<'a, str>),
pub f: mac!(Cow<'a, str>),
}
#[derive(Serialize)]
#[allow(dead_code)]
struct Struct {
pub struct Struct {
#[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>,
pub vec: Vec<Self>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
struct GenericUnitStruct<const N: usize>;
pub struct GenericUnitStruct<const N: usize>;
}
//////////////////////////////////////////////////////////////////////////
@@ -865,7 +894,7 @@ where
#[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
pub enum InternallyTagged {
#[serde(deserialize_with = "deserialize_generic")]
Unit,
File diff suppressed because it is too large Load Diff
+15
View File
@@ -7,14 +7,17 @@ mod remote {
pub struct PrimitivePriv(u8);
#[allow(dead_code)]
pub struct PrimitivePub(pub u8);
pub struct NewtypePriv(Unit);
#[allow(dead_code)]
pub struct NewtypePub(pub Unit);
pub struct TuplePriv(u8, Unit);
#[allow(dead_code)]
pub struct TuplePub(pub u8, pub Unit);
pub struct StructPriv {
@@ -22,6 +25,7 @@ mod remote {
b: Unit,
}
#[allow(dead_code)]
pub struct StructPub {
pub a: u8,
pub b: Unit,
@@ -86,12 +90,14 @@ mod remote {
}
}
#[allow(dead_code)]
pub enum EnumGeneric<T> {
Variant(T),
}
}
#[derive(Serialize, Deserialize)]
#[allow(dead_code)]
struct Test {
#[serde(with = "UnitDef")]
unit: remote::Unit,
@@ -132,6 +138,7 @@ struct Test {
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::Unit")]
#[allow(dead_code)]
struct UnitDef;
#[derive(Serialize, Deserialize)]
@@ -140,6 +147,7 @@ struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePub")]
#[allow(dead_code)]
struct PrimitivePubDef(u8);
#[derive(Serialize, Deserialize)]
@@ -148,6 +156,7 @@ struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitD
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePub")]
#[allow(dead_code)]
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
@@ -159,6 +168,7 @@ struct TuplePrivDef(
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePub")]
#[allow(dead_code)]
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
@@ -174,6 +184,7 @@ struct StructPrivDef {
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")]
#[allow(dead_code)]
struct StructPubDef {
a: u8,
@@ -190,17 +201,20 @@ struct StructGenericWithGetterDef<T> {
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructGeneric<u8>")]
#[allow(dead_code)]
struct StructConcrete {
value: u8,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::EnumGeneric<u8>")]
#[allow(dead_code)]
enum EnumConcrete {
Variant(u8),
}
#[derive(Debug)]
#[allow(dead_code)]
enum ErrorKind {
NotFound,
PermissionDenied,
@@ -211,6 +225,7 @@ enum ErrorKind {
#[derive(Serialize, Deserialize)]
#[serde(remote = "ErrorKind")]
#[non_exhaustive]
#[allow(dead_code)]
enum ErrorKindDef {
NotFound,
PermissionDenied,
+2 -2
View File
@@ -41,7 +41,7 @@ fn test_self() {
}
#[derive(Deserialize, Serialize)]
struct Tuple(
pub struct Tuple(
Box<Self>,
Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC],
@@ -60,7 +60,7 @@ fn test_self() {
}
#[derive(Deserialize, Serialize)]
enum Enum {
pub enum Enum {
Struct {
_f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>,
+23
View File
@@ -0,0 +1,23 @@
use serde::de::Deserialize;
use serde::ser::Serialize;
fn to_string<T>(_: &T) -> String
where
T: Serialize,
{
unimplemented!()
}
fn from_str<'de, T>(_: &'de str) -> T
where
T: Deserialize<'de>,
{
unimplemented!()
}
struct MyStruct;
fn main() {
to_string(&MyStruct);
let _: MyStruct = from_str("");
}
@@ -0,0 +1,55 @@
error[E0277]: the trait bound `MyStruct: Serialize` is not satisfied
--> tests/ui/on_unimplemented.rs:21:15
|
21 | to_string(&MyStruct);
| --------- ^^^^^^^^^ the trait `Serialize` is not implemented for `MyStruct`
| |
| required by a bound introduced by this call
|
= note: for local types consider adding `#[derive(serde::Serialize)]` to your `MyStruct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `Serialize`:
&'a T
&'a mut T
()
(T,)
(T0, T1)
(T0, T1, T2)
(T0, T1, T2, T3)
(T0, T1, T2, T3, T4)
and $N others
note: required by a bound in `to_string`
--> tests/ui/on_unimplemented.rs:6:8
|
4 | fn to_string<T>(_: &T) -> String
| --------- required by a bound in this function
5 | where
6 | T: Serialize,
| ^^^^^^^^^ required by this bound in `to_string`
error[E0277]: the trait bound `MyStruct: Deserialize<'_>` is not satisfied
--> tests/ui/on_unimplemented.rs:22:23
|
22 | let _: MyStruct = from_str("");
| ^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `MyStruct`
|
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyStruct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `Deserialize<'de>`:
&'a Path
&'a [u8]
&'a str
()
(T,)
(T0, T1)
(T0, T1, T2)
(T0, T1, T2, T3)
and $N others
note: required by a bound in `from_str`
--> tests/ui/on_unimplemented.rs:13:8
|
11 | fn from_str<'de, T>(_: &'de str) -> T
| -------- required by a bound in this function
12 | where
13 | T: Deserialize<'de>,
| ^^^^^^^^^^^^^^^^ required by this bound in `from_str`