Compare commits

..

283 Commits

Author SHA1 Message Date
David Tolnay d17902059e Merge pull request #3019 from xibeiyoumian/master
chore: improve code comments clarity
2025-12-22 03:29:10 -08:00
xibeiyoumian a27948e209 chore: improve code comments clarity
Signed-off-by: xibeiyoumian <xibeiyoumian@outlook.com>
2025-12-22 14:38:55 +08:00
David Tolnay 576e2ef9d8 Update actions/upload-artifact@v5 -> v6 2025-12-19 21:10:59 -08:00
David Tolnay dd0eb0f2ca Update actions/upload-artifact@v4 -> v5 2025-12-18 18:58:13 -08:00
David Tolnay f7fc3e0d67 Update actions/checkout@v5 -> v6 2025-11-20 10:19:51 -08:00
David Tolnay 1c396d223b Update actions/checkout@v4 -> v5 2025-11-20 10:19:04 -08:00
David Tolnay e42684f9a7 Update ui test suite to nightly-2025-11-02 2025-11-01 22:38:40 -07:00
David Tolnay 56c29b3c5d Update name of empty_enum clippy lint
warning: lint `clippy::empty_enum` has been renamed to `clippy::empty_enums`
       --> serde/src/lib.rs:122:5
        |
    122 |     clippy::empty_enum,
        |     ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::empty_enums`
        |
        = note: `#[warn(renamed_and_removed_lints)]` on by default

    warning: lint `clippy::empty_enum` has been renamed to `clippy::empty_enums`
      --> serde_core/src/lib.rs:57:5
       |
    57 |     clippy::empty_enum,
       |     ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::empty_enums`
       |
       = note: `#[warn(renamed_and_removed_lints)]` on by default

    warning: lint `clippy::empty_enum` has been renamed to `clippy::empty_enums`
     --> test_suite/tests/test_de.rs:5:5
      |
    5 |     clippy::empty_enum,
      |     ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::empty_enums`
      |
      = note: `#[warn(renamed_and_removed_lints)]` on by default

    warning: lint `clippy::empty_enum` has been renamed to `clippy::empty_enums`
     --> test_suite/tests/test_de_error.rs:3:5
      |
    3 |     clippy::empty_enum,
      |     ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::empty_enums`
      |
      = note: `#[warn(renamed_and_removed_lints)]` on by default
2025-11-01 22:37:05 -07:00
David Tolnay 5a44519a9a Raise required compiler for serde_derive to Rust 1.68 2025-10-19 15:02:17 -07:00
David Tolnay fae23fea97 Resolve manual_let_else pedantic clippy lint
warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1460:5
         |
    1460 | /     let string = match get_lit_str(cx, attr_name, meta)? {
    1461 | |         Some(string) => string,
    1462 | |         None => return Ok(None),
    1463 | |     };
         | |______^ help: consider writing: `let Some(string) = get_lit_str(cx, attr_name, meta)? else { return Ok(None) };`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
         = note: `-W clippy::manual-let-else` implied by `-W clippy::pedantic`
         = help: to override `-W clippy::pedantic` add `#[allow(clippy::manual_let_else)]`

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1482:5
         |
    1482 | /     let string = match get_lit_str(cx, attr_name, meta)? {
    1483 | |         Some(string) => string,
    1484 | |         None => return Ok(None),
    1485 | |     };
         | |______^ help: consider writing: `let Some(string) = get_lit_str(cx, attr_name, meta)? else { return Ok(None) };`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1505:5
         |
    1505 | /     let string = match get_lit_str2(cx, attr_name, meta_item_name, meta)? {
    1506 | |         Some(string) => string,
    1507 | |         None => return Ok(Vec::new()),
    1508 | |     };
         | |______^ help: consider writing: `let Some(string) = get_lit_str2(cx, attr_name, meta_item_name, meta)? else { return Ok(Vec::new()) };`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1526:5
         |
    1526 | /     let string = match get_lit_str(cx, attr_name, meta)? {
    1527 | |         Some(string) => string,
    1528 | |         None => return Ok(None),
    1529 | |     };
         | |______^ help: consider writing: `let Some(string) = get_lit_str(cx, attr_name, meta)? else { return Ok(None) };`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1549:5
         |
    1549 | /     let string = match get_lit_str(cx, BORROW, meta)? {
    1550 | |         Some(string) => string,
    1551 | |         None => return Ok(BTreeSet::new()),
    1552 | |     };
         | |______^ help: consider writing: `let Some(string) = get_lit_str(cx, BORROW, meta)? else { return Ok(BTreeSet::new()) };`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1621:5
         |
    1621 | /     let seg = match path.segments.last() {
    1622 | |         Some(seg) => seg,
    1623 | |         None => {
    1624 | |             return false;
    1625 | |         }
    1626 | |     };
         | |______^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
    help: consider writing
         |
    1621 ~     let Some(seg) = path.segments.last() else {
    1622 +             return false;
    1623 +         };
         |

    warning: this could be rewritten as `let...else`
        --> serde_derive/src/internals/attr.rs:1648:5
         |
    1648 | /     let seg = match path.segments.last() {
    1649 | |         Some(seg) => seg,
    1650 | |         None => {
    1651 | |             return false;
    1652 | |         }
    1653 | |     };
         | |______^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
    help: consider writing
         |
    1648 ~     let Some(seg) = path.segments.last() else {
    1649 +             return false;
    1650 +         };
         |

    warning: this could be rewritten as `let...else`
      --> serde_derive/src/internals/ctxt.rs:49:9
       |
    49 | /         let mut combined = match errors.next() {
    50 | |             Some(first) => first,
    51 | |             None => return Ok(()),
    52 | |         };
       | |__________^ help: consider writing: `let Some(mut combined) = errors.next() else { return Ok(()) };`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
      --> serde_derive/src/de.rs:29:5
       |
    29 | /     let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize, &private...
    30 | |         Some(cont) => cont,
    31 | |         None => return Err(ctxt.check().unwrap_err()),
    32 | |     };
       | |______^ help: consider writing: `let Some(cont) = Container::from_ast(&ctxt, input, Derive::Deserialize, &private.ident()) else { return Err(ctxt.check().unwrap_err()) };`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else

    warning: this could be rewritten as `let...else`
      --> serde_derive/src/ser.rs:16:5
       |
    16 | /     let cont = match Container::from_ast(&ctxt, input, Derive::Serialize, &private.i...
    17 | |         Some(cont) => cont,
    18 | |         None => return Err(ctxt.check().unwrap_err()),
    19 | |     };
       | |______^ help: consider writing: `let Some(cont) = Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident()) else { return Err(ctxt.check().unwrap_err()) };`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
2025-10-19 15:02:16 -07:00
David Tolnay d656b4dd6a Raise required compiler for serde_derive to Rust 1.65 2025-10-19 15:02:12 -07:00
David Tolnay b517ec9fd7 Merge pull request #3001 from nik-contrib/refactor
refactor: remove 1 level of nesting
2025-10-17 10:35:18 -07:00
Nik Revenco 086353c581 refactor: remove 1 level of nesting 2025-10-17 18:29:26 +01:00
David Tolnay 4e278703c6 Merge pull request #2936 from Mingun/remove-fixme
Remove some ? from generated code
2025-09-28 11:34:47 -07:00
Mingun 9f9a1ea35e Do not use ? operator in the generated code where possible
This may slightly improve compilation time and costs nothing
2025-09-28 23:21:26 +05:00
David Tolnay a866b336f1 Release 1.0.228 2025-09-27 09:51:07 -07:00
David Tolnay 5adc9e816c Merge pull request #2995 from dtolnay/rustdocflags
Workaround for RUSTDOCFLAGS='--cfg=docsrs'
2025-09-27 09:50:33 -07:00
David Tolnay ab581789f4 Workaround for RUSTDOCFLAGS='--cfg=docsrs' 2025-09-27 09:46:14 -07:00
David Tolnay 415d9fc560 Release 1.0.227 2025-09-25 16:42:33 -07:00
David Tolnay 7c58427e12 Merge pull request #2991 from dtolnay/inlinecoredoc
Inline serde_core into serde in docsrs mode
2025-09-25 16:41:35 -07:00
David Tolnay 9d3410e3f4 Merge pull request #2992 from dtolnay/inplaceseed
Remove InPlaceSeed public re-export
2025-09-25 16:40:54 -07:00
David Tolnay 2fb6748bf1 Remove InPlaceSeed public re-export 2025-09-25 16:26:14 -07:00
David Tolnay f8137c79a2 Inline serde_core into serde in docsrs mode 2025-09-25 13:22:15 -07:00
David Tolnay b7dbf7e3cb Merge pull request #2990 from dtolnay/integer128
No longer macro_use integer128 module
2025-09-25 11:14:43 -07:00
David Tolnay 7c836915fc No longer macro_use integer128 module 2025-09-25 11:09:19 -07:00
David Tolnay aa2d9b208a Merge pull request #2989 from dtolnay/pr2987
PR 2987 followup
2025-09-25 09:45:25 -07:00
David Tolnay 3a7c11c82c Rename enum_untagged::generate_newtype_variant -> deserialize_newtype_variant 2025-09-25 09:41:34 -07:00
David Tolnay 11ce4402bd Rename enum_untagged::generate_variant -> deserialize_variant 2025-09-25 09:41:34 -07:00
David Tolnay 8047570160 Rename generate_body_in_place -> deserialize_in_place 2025-09-25 09:41:34 -07:00
David Tolnay b395215875 Rename all other generate_body -> deserialize 2025-09-25 09:41:33 -07:00
David Tolnay a437ff6bf7 Rename identifier::generate_identifier -> deserialize_generated 2025-09-25 09:41:33 -07:00
David Tolnay 20fc31c78a Rename identifier::generate_body -> deserialize_custom 2025-09-25 09:41:33 -07:00
David Tolnay ad2b064b0a Adjust variable names 2025-09-25 09:41:33 -07:00
David Tolnay dec153b8fa Adjust comments 2025-09-25 09:41:33 -07:00
David Tolnay e219a0d4b7 Replace unnecessary use of generics_with_de_lifetime 2025-09-25 09:41:33 -07:00
David Tolnay c78f7d2e30 Rename Parameters::generics -> generics_with_de_lifetime 2025-09-25 09:41:33 -07:00
David Tolnay 502a065a4c Merge pull request #2987 from Mingun/split-de-generator
Refactor: split de generator over multiple files
2025-09-25 09:41:29 -07:00
Mingun 027112eccb Visibility fix for Rust 1.61 2025-09-21 20:58:53 +05:00
Mingun 8c3445efe4 Group some functions that used together 2025-09-21 20:40:22 +05:00
Mingun 88b6a9abf4 Rename functions and run cargo fmt 2025-09-21 20:40:21 +05:00
Mingun fa298c9df4 Move generator for identifiers to its own module
Cut-paste
2025-09-21 20:40:21 +05:00
Mingun c4a07ed4e8 Move body generator for unit structs to its own module
Cut-paste
2025-09-21 20:40:21 +05:00
Mingun c4986f10b9 Move body generator for tuple structs to its own module
Cut-paste
2025-09-21 20:40:21 +05:00
Mingun 2d607de146 Move body generator for structs to its own module
Cut-paste
2025-09-21 20:40:21 +05:00
Mingun 19956e6b8e Move body generator for enums to its own module
Cut-paste
2025-09-21 20:40:20 +05:00
Mingun ec13eb4ed6 Move body generator for untagged enums to its own module
Cut-paste
2025-09-21 20:40:20 +05:00
Mingun ae00c4acb7 Move body generator for internally tagged enums to its own module
Cut-paste
2025-09-21 20:40:20 +05:00
Mingun 85d0b9ccd8 Move body generator for externally tagged enums to its own module
Cut-paste
2025-09-21 20:40:20 +05:00
Mingun e60f62a289 Move body generator for adjacently tagged enums to its own module
Cut-paste
2025-09-21 20:40:20 +05:00
Mingun e04f0ba2de StructForm::InternallyTagged always instantiated with the same deserializer, so remove that parameter 2025-09-21 20:40:20 +05:00
Mingun c8184be238 StructForm::Untagged always instantiated with the same deserializer, so remove that parameter 2025-09-21 20:40:19 +05:00
Mingun 896d91f0bb TupleForm::Untagged always instantiated with the same deserializer, so remove that parameter 2025-09-21 20:40:19 +05:00
Mingun 915686d0ec deserialize_untagged_newtype_variant always called with the same deserializer, so remove that parameter 2025-09-21 20:40:19 +05:00
Mingun 3a682c951b deserialize_untagged_variant always called with the same deserializer, so remove that parameter 2025-09-21 20:40:19 +05:00
Mingun ca79f61d0f deserialize_internally_tagged_variant always called with the same deserializer, so remove that parameter 2025-09-21 20:40:19 +05:00
Mingun ddb7c4b30f Convert split_with_de_lifetime to method of Parameters 2025-09-21 15:39:11 +05:00
Mingun 4855fb467f Move code for injecting tagged variants to untagged generator to the place where the decision was made 2025-09-21 15:39:11 +05:00
Mingun 6dffc0b1c8 Remove one-line intermediate function 2025-09-21 15:39:11 +05:00
Mingun 15be2a600a Remove confusing call to deserialize_untagged_variant in deserialize_internally_tagged_variant
deserialize_untagged_variant in that place is called when deserialzie_with attribute is set.
In that case it performs special actions that is better to use explicitly in deserialize_untagged_variant
for readability
2025-09-21 15:39:11 +05:00
David Tolnay 1799547846 Release 1.0.226 2025-09-20 16:34:44 -07:00
David Tolnay 2dbeefb11b Merge pull request #2935 from Mingun/dedupe-adj-enums
Remove code duplication when deriving Deserialize for adjacently tagged enums
2025-09-20 16:33:32 -07:00
David Tolnay 8a3c29ff19 Merge pull request #2986 from dtolnay/didnotwork
Remove "did not work" comment from test suite
2025-09-20 12:30:39 -07:00
David Tolnay defc24d361 Remove "did not work" comment from test suite 2025-09-20 12:23:01 -07:00
Oli Scherer 2316610760 Merge pull request #2929 from Mingun/flatten-enum-tests
Add more tests for flatten enums to increase test coverage
2025-09-18 13:15:10 +00:00
Mingun c09e2bd690 Add tests for flatten unit variant in adjacently tagged (tag + content) enums 2025-09-17 23:53:07 +05:00
Mingun fe7dcc4cd8 Test all possible orders of map entries for enum-flatten-in-struct representations 2025-09-17 23:51:30 +05:00
Mingun a20e66e131 Check serialization in flatten::enum_::internally_tagged::unit_enum_with_unknown_fields 2025-09-17 23:50:00 +05:00
Mingun 1c1a5d95cd Reorder struct_ and newtype tests of adjacently_tagged enums to match order in Enum 2025-09-17 23:48:23 +05:00
David Tolnay ee3c2372fb Opt in to generate-macro-expansion when building on docs.rs 2025-09-16 16:29:21 -07:00
Mingun bfb020d975 Use variant name for field instead of field 2025-09-17 00:09:51 +05:00
Mingun 6805bba308 Inline variables that used only once 2025-09-17 00:09:14 +05:00
Mingun 2659b94a62 Create deserializer only when needed 2025-09-17 00:08:07 +05:00
Mingun c451415d9f Do not duplicate variant deserialization code 2025-09-17 00:07:00 +05:00
Mingun 553a9ff15f Document functions that are entry points for generating bodies of different deserialization forms 2025-09-17 00:05:53 +05:00
David Tolnay 6f5eb7d207 Merge pull request #2983 from Mingun/fix-test-instructions
Fix instructions for testing contributions
2025-09-16 09:24:04 -07:00
Mingun 55615e8f8e Fix instructions for testing contributions
Since separation of serde_core from serde, all doctests lives in serde_core project,
which also does not have the `derive` feature. Following the old instructions does not
run any tests.
2025-09-16 21:15:49 +05:00
David Tolnay 1d7899d671 Release 1.0.225 2025-09-15 20:43:08 -07:00
David Tolnay 97168d3a24 Touch up PR 2879 2025-09-15 20:38:57 -07:00
David Tolnay 373b11dda7 Merge pull request 2879 from rcrisanti/fix/silence-deprecation-warnings-derive 2025-09-15 20:26:40 -07:00
David Tolnay 69072f2423 Merge pull request 2931 from Mingun/unify-serde-access 2025-09-15 13:22:24 -07:00
David Tolnay 5b37e8a531 Merge pull request #2980 from dtolnay/private
Use differently named __private module per patch release
2025-09-15 13:20:54 -07:00
Mingun b47f4dfa96 Unify access to the serde namespace
In other places `_serde` name is used to access the `serde` crate, so use it there
2025-09-16 00:36:12 +05:00
David Tolnay cbe98a9888 Use differently named __private module per patch release 2025-09-15 09:53:14 -07:00
David Tolnay 957996f5fb Make all use of __private go through interpolation 2025-09-15 09:48:26 -07:00
David Tolnay 169988206a Release 1.0.224 2025-09-15 08:46:21 -07:00
David Tolnay 840f6ec9b8 Merge pull request #2979 from dtolnay/private
Mark every trait impl for a private type with do_not_recommend
2025-09-15 08:45:06 -07:00
David Tolnay bf9ebea392 Mark every trait impl for a private type with do_not_recommend 2025-09-14 19:47:36 -07:00
David Tolnay 6c316d7cb5 Release 1.0.223 2025-09-14 13:20:31 -07:00
David Tolnay a4ac0c2bc6 Merge pull request #2978 from dtolnay/htmlrooturl
Change serde_core's html_root_url to docs.rs/serde_core
2025-09-14 13:19:52 -07:00
David Tolnay ed76364f87 Change serde_core's html_root_url to docs.rs/serde_core 2025-09-14 12:54:38 -07:00
David Tolnay 57e21a1afa Release 1.0.222 2025-09-14 11:09:08 -07:00
David Tolnay bb58726133 Merge pull request #2950 from aytey/fix_lifetime_issue_2024
Fix temporary value lifetime in `serialize_struct`
2025-09-14 11:08:16 -07:00
David Tolnay 3f6925125b Delete unneeded field of MapDeserializer 2025-09-14 08:39:57 -07:00
David Tolnay fd4decf2fe Merge pull request #2976 from dtolnay/content
Move Content's Deserialize impl from serde_core to serde
2025-09-14 08:39:46 -07:00
David Tolnay 00b1b6b2b5 Move Content's Deserialize impl from serde_core to serde 2025-09-14 08:35:53 -07:00
David Tolnay cf141aa8c7 Move Content's Clone impl from serde_core to serde 2025-09-14 08:35:32 -07:00
David Tolnay ff3aee490a Release 1.0.221 2025-09-13 17:25:20 -07:00
David Tolnay 10bcfc0047 Merge pull request #2975 from dtolnay/integer128
Deprecate serde_if_integer128 macro
2025-09-13 17:25:14 -07:00
David Tolnay 2f03899197 Deprecate serde_if_integer128 macro 2025-09-13 17:19:10 -07:00
David Tolnay 3bea3b6989 Move serde_if_integer128 macro to serde 2025-09-13 17:12:58 -07:00
David Tolnay 85bf29c446 Merge pull request #2973 from dtolnay/timings
Illustrate build timings in serde_core readme
2025-09-13 17:12:51 -07:00
David Tolnay 900c922f41 Illustrate build timings in serde_core readme 2025-09-13 17:09:47 -07:00
David Tolnay 9cf3f2ed7d Merge pull request #2974 from dtolnay/patchserdecore
Patch serde_core at workspace level
2025-09-13 17:04:36 -07:00
David Tolnay 1ffbeb9516 Patch serde_core at workspace level 2025-09-13 16:59:44 -07:00
David Tolnay 1051c5e6b7 Enforce trybuild >= 1.0.108
Older versions produce slightly differently normalized output
when run against 1.90.0+ Rust compiler.
2025-09-13 14:49:14 -07:00
David Tolnay be255d62c8 Release 1.0.220 2025-09-13 14:45:43 -07:00
David Tolnay 263a1dbdd7 Link to serde.rs without trailing slash 2025-09-13 14:40:22 -07:00
David Tolnay 23dea60e1a Merge pull request #2971 from dtolnay/serdecoreci
Add CI coverage of serde_core
2025-09-13 14:40:13 -07:00
David Tolnay 690785f129 Add CI coverage of serde_core 2025-09-13 14:36:11 -07:00
David Tolnay 69aa109fd3 Merge pull request #2970 from dtolnay/coredoctest
Fix serde_core doc tests
2025-09-13 14:36:00 -07:00
David Tolnay 6bea2e04e4 Move doc helper macros to serde_core 2025-09-13 14:32:21 -07:00
David Tolnay a1a82c3c55 Replace serde_core::* glob export 2025-09-13 14:32:21 -07:00
David Tolnay 7987ad700e Fix serde_core doc tests 2025-09-13 14:32:21 -07:00
David Tolnay 0990d97a77 Merge pull request #2969 from dtolnay/coreprivate
Reduce visibility of serde_core implementation details
2025-09-13 14:32:12 -07:00
David Tolnay a9150aad74 Make serde_core::Result private 2025-09-13 14:29:23 -07:00
David Tolnay 5ac3d84d99 Make InPlaceSeed private 2025-09-13 14:29:23 -07:00
David Tolnay f916ec6baa Make size_hint private 2025-09-13 14:29:22 -07:00
David Tolnay 7f831225a9 Make from_utf8_lossy private 2025-09-13 14:29:01 -07:00
David Tolnay a16893429b Make module for Content-related private code 2025-09-13 14:26:58 -07:00
David Tolnay 260511d149 Merge pull request #2968 from dtolnay/deserializecontent
Restore `__deserialize_content` optimization
2025-09-13 14:26:50 -07:00
David Tolnay 7659fb686d Inline SeqDeserializer and MapDeserializer for Content
Greatly shrinks symbol sizes: keep all those generic type parameters
(and even closures) out of symbol names. A good change even independent
of serde_core.
2025-09-13 14:22:33 -07:00
David Tolnay f669f16127 Restore __deserialize_content optimization 2025-09-13 14:22:33 -07:00
David Tolnay 93f43cedaa Merge pull request #2967 from dtolnay/tricfg
Specify the cfg in which `tri!` is used
2025-09-13 14:22:25 -07:00
David Tolnay b6c7ce8ec3 Specify the cfg in which 'tri!' is used 2025-09-13 14:19:07 -07:00
David Tolnay 35c963101b Merge pull request #2966 from dtolnay/noserdecore
Enforce derive cannot be used against serde_core
2025-09-13 14:19:01 -07:00
David Tolnay 8909fc0c60 Enforce derive cannot be used against serde_core
Even for a simple data structure that would ordinarily expand to an impl
that only refers to the public Serde traits without serde::__private, we
still disallow a (renamed) serde_core dependency. This leaves the
liberty to new usage of private helpers in such impls over time. For
example, similar to the optimization of the standard library's
derive(Debug) that introduced debug_struct_field1_finish to improve
compile time of derived impls.
2025-09-13 14:15:44 -07:00
David Tolnay 3c747e4585 Relocate serde_derive version constraint from serde to serde_core
This disallows using an old version of serde_derive against a new
version of serde_core (with a rename to serde in Cargo.toml).
2025-09-13 14:15:44 -07:00
David Tolnay 1b89ff50a9 Merge pull request #2965 from dtolnay/enableresult
Forcibly enable serde_core/result when using serde
2025-09-13 14:15:38 -07:00
David Tolnay c069b5c640 Forcibly enable serde_core/result when using serde
Making Result impls get disabled when using `serde = { version = "1",
default-features = false }` would have been a breaking change.
2025-09-13 14:11:44 -07:00
David Tolnay 79f3484ab8 Merge pull request #2964 from dtolnay/serdecoredoc
Update documentation of serde_core
2025-09-13 14:11:33 -07:00
David Tolnay ac8b7ea052 Update serde_core package.description in Cargo.toml 2025-09-13 14:07:54 -07:00
David Tolnay c1b2f43917 Tweak explanation of "result" feature 2025-09-13 14:07:54 -07:00
David Tolnay 51f8b0c52d Rewrite serde_core readme 2025-09-13 14:07:53 -07:00
David Tolnay 6c4cae6b09 Point API documentation to docs.rs/serde 2025-09-13 14:07:53 -07:00
David Tolnay 4da055a286 Fix broken link in serde_core crates.io readme 2025-09-13 14:07:53 -07:00
David Tolnay 66c5d2b153 Merge pull request #2963 from dtolnay/diagnosticpath
Override diagnostic::on_unimplemented message for all serde_core traits
2025-09-13 14:07:43 -07:00
David Tolnay 4bddf1b953 Override diagnostic::on_unimplemented message of all serde_core traits
This prevents diagnostics being rendered like `serde_core::ser::Serialize`
and `serde_core::de::Deserialize` in projects that have no direct
dependency on serde_core.

The attributes make error messages arguably sometimes worse than
pre-serde_core by always rendering `serde::Serialize` and never
`Serialize` when `use serde::Serialize` is in scope, which rustc's
default message construction knows to recognize. But this is probably
negligible.

I explored the alternative of setting `[lib] name = "serde"` in
serde_core/Cargo.toml which also prevents `serde_core::ser::Serialize`
in messages, but has the unwanted effect of also inserting the following
noise into every such error:

    note: there are multiple different versions of crate `serde` in the dependency graph
        --> $WORKSPACE/serde_core/src/ser/mod.rs:225:1
         |
     225 | pub trait Serialize {
         | ^^^^^^^^^^^^^^^^^^^ this is the required trait
         |
        ::: src/main.rs:1:1
         |
       1 | struct MyStruct;
         | --------------- this type doesn't implement the required trait
    ...
       4 |     let _ = serde_json::to_string(&MyStruct);
         |             ----------
         |             |
         |             one version of crate `serde` used here, as a dependency of crate `serde`
         |             one version of crate `serde` used here, as a dependency of crate `serde_json`
         |
        ::: $WORKSPACE/serde/src/private/de.rs:2347:1
         |
    2347 | pub trait IdentifierDeserializer<'de, E: Error> {
         | ----------------------------------------------- this is the found trait
         = help: you can use `cargo tree` to explore your dependency tree

The "this is the found trait" pointing to `IdentifierDeserializer` seems
like a compiler bug...
2025-09-13 13:59:52 -07:00
David Tolnay 908f32175a Add ui test of unimplemented trait required by dependency 2025-09-13 13:59:52 -07:00
David Tolnay 3e1cf11060 Organize on_unimplemented ui test into directory 2025-09-13 13:59:52 -07:00
David Tolnay 723fcacad7 Merge pull request #2608 from osiewicz/extract_serde_core
feat: Extract serde_core out of serde crate
2025-09-13 13:59:17 -07:00
David Tolnay 94acfe19e6 Format with rustfmt 1.8.0-nightly 2025-09-13 10:16:16 -07:00
Oli Scherer b4677fde9d Bump outdated test dependency 2025-08-26 08:02:38 +00:00
Oli Scherer c85e4240be Allow more dead code 2025-08-26 07:19:59 +00:00
Oli Scherer 363deb84cc Work around dead code warnings 2025-08-26 07:10:49 +00:00
Andrew V. Teylu 106da4905f Fix temporary value lifetime in serialize_struct
In the 2024 edition of Rust, `serde`s macros for `serialize_with` can
lead to a temporary lifetime error such as:

```
error[E0716]: temporary value dropped while borrowed
 --> my-binary/src/main.rs:6:10
  |
6 | #[derive(MyDerive)]
  |          ^^^^^^^-
  |          |      |
  |          |      temporary value is freed at the end of this statement
  |          creates a temporary value which is freed while still in use
  |          borrow later used by call
  |          in this derive macro expansion
  |
 ::: /private/tmp/life/my-project/my-macro/src/lib.rs:6:1
  |
6 | pub fn my_derive(_input: TokenStream) -> TokenStream {
  | ---------------------------------------------------- in this expansion of `#[derive(MyDerive)]`
  |
  = note: consider using a `let` binding to create a longer lived value
```

This is because the macro code takes a reference to struct inside of a
block, which then goes out of scope when `serde` passes it to a
function.

To resolve this, we move the reference to outside of the block, to
ensure that the lifetime extends into the function call.

Signed-off-by: Andrew V. Teylu <andrew.teylu@vector.com>
2025-08-01 10:03:16 +01:00
Piotr Osiewicz f9baf39dc3 review: Update crates-io.md 2025-06-06 12:15:59 +02:00
Piotr Osiewicz 3deb08946e review: Gate Result impls behind a feature gate 2025-06-06 11:57:32 +02:00
Piotr Osiewicz 43f5eb5c69 review: Bring back old doc comment for serde_core 2025-06-06 11:57:32 +02:00
Piotr Osiewicz 5fcfbed3ea review: Update license symlinks 2025-06-06 11:57:32 +02:00
Piotr Osiewicz f3869307cc feat: extract serde_core out of serde 2025-06-06 11:57:32 +02:00
Oli Scherer babafa54d2 Merge pull request #2939 from Mingun/remove-actually-private
Remove `actually_private::T`
2025-06-06 06:39:39 +00:00
Mingun ad6c548573 Use associated type in signature to not repeat concrete type 2025-06-06 10:39:51 +05:00
Mingun 80b2f5f9e1 Remove actually_private::T
It just makes life harder in some cases without any benefits
2025-06-06 10:39:51 +05:00
David Tolnay 2130ba5788 Ignore mismatched_lifetime_syntaxes lint
warning: lifetime flowing from input to output with different syntax can be confusing
       --> serde/src/private/de.rs:266:23
        |
    266 |         fn unexpected(&self) -> Unexpected {
        |                       ^^^^^     ---------- the lifetime gets resolved as `'_`
        |                       |
        |                       this lifetime flows to the output
        |
        = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
    help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
        |
    266 |         fn unexpected(&self) -> Unexpected<'_> {
        |                                           ++++

    warning: lifetime flowing from input to output with different syntax can be confusing
      --> serde/src/private/mod.rs:27:35
       |
    27 |     pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
       |                                   ^^^^^     -------- the lifetime gets resolved as `'_`
       |                                   |
       |                                   this lifetime flows to the output
       |
    help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
       |
    27 |     pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> {
       |                                                 +++

    warning: lifetime flowing from input to output with different syntax can be confusing
       --> serde_derive/src/internals/attr.rs:612:23
        |
    612 |     pub fn serde_path(&self) -> Cow<syn::Path> {
        |                       ^^^^^     -------------- the lifetime gets resolved as `'_`
        |                       |
        |                       this lifetime flows to the output
        |
        = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
    help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
        |
    612 |     pub fn serde_path(&self) -> Cow<'_, syn::Path> {
        |                                     +++

    warning: lifetime flowing from input to output with different syntax can be confusing
      --> serde_derive/src/internals/case.rs:45:37
       |
    45 |     pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
       |                                     ^^^^                  ---------- the lifetime gets resolved as `'_`
       |                                     |
       |                                     this lifetime flows to the output
       |
    help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
       |
    45 |     pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError<'_>> {
       |                                                                     ++++

    warning: lifetime flowing from input to output with different syntax can be confusing
        --> serde_derive/src/de.rs:3228:13
         |
    3228 |     params: &Parameters,
         |             ^^^^^^^^^^^ this lifetime flows to the output
    3229 | ) -> (
    3230 |     DeImplGenerics,
         |     -------------- the lifetimes get resolved as `'_`
    3231 |     DeTypeGenerics,
         |     -------------- the lifetimes get resolved as `'_`
    3232 |     syn::TypeGenerics,
         |     ----------------- the lifetimes get resolved as `'_`
    3233 |     Option<&syn::WhereClause>,
         |            ----------------- the lifetimes get resolved as `'_`
         |
    help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
         |
    3230 ~     DeImplGenerics<'_>,
    3231 ~     DeTypeGenerics<'_>,
    3232 ~     syn::TypeGenerics<'_>,
         |
2025-06-05 22:11:48 -07:00
David Tolnay a1ddb18c92 Resolve new dead_code warnings in test suite
Bisects to https://github.com/rust-lang/rust/pull/141407.

    warning: struct `Struct` is never constructed
       --> test_suite/tests/test_gen.rs:803:16
        |
    803 |     pub struct Struct {
        |                ^^^^^^
        |
        = note: `#[warn(dead_code)]` on by default

    warning: function `vec_first_element` is never used
       --> test_suite/tests/test_gen.rs:885:4
        |
    885 | fn vec_first_element<T, S>(vec: &[T], serializer: S) -> StdResult<S::Ok, S::Error>
        |    ^^^^^^^^^^^^^^^^^

    warning: struct `S` is never constructed
     --> test_suite/tests/regression/issue2415.rs:5:12
      |
    5 | pub struct S;
      |            ^
      |
      = note: `#[warn(dead_code)]` on by default
2025-05-31 10:09:26 -07:00
Ryan Crisanti ae38b27aee add #[allow(deprecated)] to derive implementations
Allow deprecated in the `Serialize`/`Deserialize`
derive implementations. This allows you to
deprecate structs, enums, struct fields, or enum
variants and not get compiler warnings/errors
about use of deprecated thing. We only do this
if `#[deprecated]` or `#[allow(deprecated)]` exist
on the root object or the variants of the root
object (if it is an enum).

Resolves #2195
2025-05-30 15:01:14 -04:00
David Tolnay da3998acfb Pin nightly toolchain used for miri job 2025-05-17 23:14:01 +02:00
Oli Scherer b9de3658ad Merge pull request #2919 from vishal-kr-barnwal/master
Update a Rust edition to 2021 across project files
2025-04-27 08:13:10 +00:00
Vishal Kumar 16af2d9ce7 Update a Rust edition to 2021 across project files
Updated the Cargo.toml files for test suites and a link in the README to use Rust edition 2021 instead of 2018. This ensures compatibility with the latest Rust features and standards.
2025-04-27 12:31:12 +05:30
David Tolnay b426ff81e3 Merge pull request #2913 from dtolnay/nightlywindows
Drop trailing whitespace from CI job name
2025-03-26 09:24:38 +00:00
David Tolnay b0e87aeecd Drop trailing whitespace from CI job name 2025-03-26 02:19:55 -07:00
David Tolnay a685dcf680 Merge pull request #2910 from jimmycathy/master
chore: fix the incorrect symbol
2025-03-16 00:05:43 -07:00
jimmycathy 88da17ca21 chore: fix the incorrect symbol
Signed-off-by: jimmycathy <clonecode@outlook.com>
2025-03-16 13:42:10 +08:00
David Tolnay d91f8ba950 Drop unused no_float_copysign cfg
Stable since Rust 1.35.
2025-03-09 12:39:05 -07:00
David Tolnay aa5aa611d4 Touch up PR 2901 2025-03-09 12:37:59 -07:00
David Tolnay da0b473d60 Merge pull request #2901 from serde-rs/msrv-and-edition-bump
MSRV (1.56) and edition (2021) bump
2025-03-09 15:37:44 -04:00
David Tolnay 49d098debd Release 1.0.219 2025-03-09 12:05:01 -07:00
David Tolnay 40f1d19dbe Wrap dummy.rs to 80 columns 2025-03-09 12:04:24 -07:00
David Tolnay 514848b584 Merge pull request #2906 from davidzeng0/master
fix clippy absolute paths warning
2025-03-09 15:03:19 -04:00
ilikdoge 168b6cf789 fix clippy absolute paths warning 2025-03-08 22:25:23 -08:00
Oli Scherer 8b0e95b6de clippy 2025-03-05 10:07:07 +00:00
Oli Scherer e3a4165363 Switch all crates to edition 2021 2025-03-05 09:51:32 +00:00
Oli Scherer 6ac8049b92 clippy 2025-03-05 09:58:12 +00:00
Oli Scherer 13a33b3c33 Bump MSRV to 1.56
This is the first cargo version that actually enforces the rust-version field in Cargo.toml
2025-03-05 09:23:29 +00:00
David Tolnay a8bdd17333 Remove unused Punctuated import
warning: unused import: `syn::punctuated::Punctuated`
     --> serde_derive/src/internals/receiver.rs:5:5
      |
    5 | use syn::punctuated::Punctuated;
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |
      = note: `#[warn(unused_imports)]` on by default

Left by the previous commit.

-        let segments = mem::replace(&mut path.segments, Punctuated::new());
+        let segments = mem::take(&mut path.segments);
2025-03-03 00:05:40 -08:00
David Tolnay 1c9601358b Resolve mem_replace_with_default clippy lint
warning: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
      --> serde_derive/src/internals/receiver.rs:52:24
       |
    52 |         let segments = mem::replace(&mut path.segments, Punctuated::new());
       |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut path.segments)`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
       = note: `-W clippy::mem-replace-with-default` implied by `-W clippy::all`
       = help: to override `-W clippy::all` add `#[allow(clippy::mem_replace_with_default)]`
2025-03-03 00:00:24 -08:00
David Tolnay f0d1ae08f3 Ignore elidable_lifetime_names pedantic clippy lint
warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:124:6
        |
    124 | impl<'de, E> IntoDeserializer<'de, E> for ()
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
        = note: `-W clippy::elidable-lifetime-names` implied by `-W clippy::pedantic`
        = help: to override `-W clippy::pedantic` add `#[allow(clippy::elidable_lifetime_names)]`
    help: elide the lifetimes
        |
    124 - impl<'de, E> IntoDeserializer<'de, E> for ()
    124 + impl<E> IntoDeserializer<'_, E> for ()
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:178:6
        |
    178 | impl<'de, E> IntoDeserializer<'de, E> for UnitDeserializer<E>
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    178 - impl<'de, E> IntoDeserializer<'de, E> for UnitDeserializer<E>
    178 + impl<E> IntoDeserializer<'_, E> for UnitDeserializer<E>
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:207:6
        |
    207 | impl<'de, E> IntoDeserializer<'de, E> for !
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    207 - impl<'de, E> IntoDeserializer<'de, E> for !
    207 + impl<E> IntoDeserializer<'_, E> for !
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:240:6
        |
    240 | impl<'de, E> IntoDeserializer<'de, E> for NeverDeserializer<E>
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    240 - impl<'de, E> IntoDeserializer<'de, E> for NeverDeserializer<E>
    240 + impl<E> IntoDeserializer<'_, E> for NeverDeserializer<E>
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:351:6
        |
    351 | impl<'de, E> IntoDeserializer<'de, E> for u32
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    351 - impl<'de, E> IntoDeserializer<'de, E> for u32
    351 + impl<E> IntoDeserializer<'_, E> for u32
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:406:6
        |
    406 | impl<'de, E> IntoDeserializer<'de, E> for U32Deserializer<E>
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    406 - impl<'de, E> IntoDeserializer<'de, E> for U32Deserializer<E>
    406 + impl<E> IntoDeserializer<'_, E> for U32Deserializer<E>
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:451:6
        |
    451 | impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    451 - impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str
    451 + impl<'a, E> IntoDeserializer<'_, E> for &'a str
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:472:11
        |
    472 | impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E>
        |           ^^                                               ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    472 - impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E>
    472 + impl<'de, E> de::Deserializer<'de> for StrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'de, 'a
       --> serde/src/de/value.rs:506:6
        |
    506 | impl<'de, 'a, E> IntoDeserializer<'de, E> for StrDeserializer<'a, E>
        |      ^^^  ^^                      ^^^                         ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    506 - impl<'de, 'a, E> IntoDeserializer<'de, E> for StrDeserializer<'a, E>
    506 + impl<E> IntoDeserializer<'_, E> for StrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:517:11
        |
    517 | impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
        |           ^^                                             ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    517 - impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
    517 + impl<'de, E> de::EnumAccess<'de> for StrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:532:6
        |
    532 | impl<'a, E> Debug for StrDeserializer<'a, E> {
        |      ^^                               ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    532 - impl<'a, E> Debug for StrDeserializer<'a, E> {
    532 + impl<E> Debug for StrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:622:6
        |
    622 | impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
        |      ^^^                                       ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    622 - impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
    622 + impl<E> Debug for BorrowedStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:653:6
        |
    653 | impl<'de, E> IntoDeserializer<'de, E> for String
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    653 - impl<'de, E> IntoDeserializer<'de, E> for String
    653 + impl<E> IntoDeserializer<'_, E> for String
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:711:6
        |
    711 | impl<'de, E> IntoDeserializer<'de, E> for StringDeserializer<E>
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    711 - impl<'de, E> IntoDeserializer<'de, E> for StringDeserializer<E>
    711 + impl<E> IntoDeserializer<'_, E> for StringDeserializer<E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:759:6
        |
    759 | impl<'a, E> Clone for CowStrDeserializer<'a, E> {
        |      ^^                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    759 - impl<'a, E> Clone for CowStrDeserializer<'a, E> {
    759 + impl<E> Clone for CowStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:770:6
        |
    770 | impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    770 - impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
    770 + impl<'a, E> IntoDeserializer<'_, E> for Cow<'a, str>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:793:11
        |
    793 | impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
        |           ^^                                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    793 - impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
    793 + impl<'de, E> de::Deserializer<'de> for CowStrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'de, 'a
       --> serde/src/de/value.rs:831:6
        |
    831 | impl<'de, 'a, E> IntoDeserializer<'de, E> for CowStrDeserializer<'a, E>
        |      ^^^  ^^                      ^^^                            ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    831 - impl<'de, 'a, E> IntoDeserializer<'de, E> for CowStrDeserializer<'a, E>
    831 + impl<E> IntoDeserializer<'_, E> for CowStrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:843:11
        |
    843 | impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
        |           ^^                                                ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    843 - impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
    843 + impl<'de, E> de::EnumAccess<'de> for CowStrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:859:6
        |
    859 | impl<'a, E> Debug for CowStrDeserializer<'a, E> {
        |      ^^                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    859 - impl<'a, E> Debug for CowStrDeserializer<'a, E> {
    859 + impl<E> Debug for CowStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:888:6
        |
    888 | impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    888 - impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
    888 + impl<'a, E> IntoDeserializer<'_, E> for &'a [u8]
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:899:11
        |
    899 | impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
        |           ^^                                             ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    899 - impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
    899 + impl<'de, E> Deserializer<'de> for BytesDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'de, 'a
       --> serde/src/de/value.rs:919:6
        |
    919 | impl<'de, 'a, E> IntoDeserializer<'de, E> for BytesDeserializer<'a, E>
        |      ^^^  ^^                      ^^^                           ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    919 - impl<'de, 'a, E> IntoDeserializer<'de, E> for BytesDeserializer<'a, E>
    919 + impl<E> IntoDeserializer<'_, E> for BytesDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:930:6
        |
    930 | impl<'a, E> Debug for BytesDeserializer<'a, E> {
        |      ^^                                 ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    930 - impl<'a, E> Debug for BytesDeserializer<'a, E> {
    930 + impl<E> Debug for BytesDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:989:6
        |
    989 | impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
        |      ^^^                                         ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    989 - impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
    989 + impl<E> Debug for BorrowedBytesDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1238:6
         |
    1238 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1238 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1238 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1255:6
         |
    1255 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1255 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1255 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1278:6
         |
    1278 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1278 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1278 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1439:6
         |
    1439 | impl<'de, I, E> Clone for MapDeserializer<'de, I, E>
         |      ^^^                                  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1439 - impl<'de, I, E> Clone for MapDeserializer<'de, I, E>
    1439 + impl<I, E> Clone for MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1456:6
         |
    1456 | impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
         |      ^^^                                  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1456 - impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
    1456 + impl<I, E> Debug for MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
      --> serde/src/de/impls.rs:17:6
       |
    17 | impl<'de> Visitor<'de> for UnitVisitor {
       |      ^^^          ^^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
       |
    17 - impl<'de> Visitor<'de> for UnitVisitor {
    17 + impl Visitor<'_> for UnitVisitor {
       |

    warning: the following explicit lifetimes could be elided: 'de
      --> serde/src/de/impls.rs:56:6
       |
    56 | impl<'de> Visitor<'de> for BoolVisitor {
       |      ^^^          ^^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
       |
    56 - impl<'de> Visitor<'de> for BoolVisitor {
    56 + impl Visitor<'_> for BoolVisitor {
       |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:550:6
        |
    550 | impl<'de> Visitor<'de> for CharVisitor {
        |      ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    550 - impl<'de> Visitor<'de> for CharVisitor {
    550 + impl Visitor<'_> for CharVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:596:6
        |
    596 | impl<'de> Visitor<'de> for StringVisitor {
        |      ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    596 - impl<'de> Visitor<'de> for StringVisitor {
    596 + impl Visitor<'_> for StringVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'a, 'de
       --> serde/src/de/impls.rs:642:6
        |
    642 | impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
        |      ^^  ^^^          ^^^                           ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    642 - impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
    642 + impl Visitor<'_> for StringInPlaceVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:953:6
        |
    953 | impl<'de, T> Visitor<'de> for PhantomDataVisitor<T>
        |      ^^^             ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    953 - impl<'de, T> Visitor<'de> for PhantomDataVisitor<T>
    953 + impl<T> Visitor<'_> for PhantomDataVisitor<T>
        |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/impls.rs:1195:14
         |
    1195 |         impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T>
         |              ^^                                             ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1195 -         impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T>
    1195 +         impl<'de, T> Visitor<'de> for VecInPlaceVisitor<'_, T>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:1838:6
         |
    1838 | impl<'de> Visitor<'de> for PathBufVisitor {
         |      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1838 - impl<'de> Visitor<'de> for PathBufVisitor {
    1838 + impl Visitor<'_> for PathBufVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/impls.rs:1991:11
         |
    1991 | impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T>
         |           ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1991 - impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T>
    1991 + impl<'de, T> Deserialize<'de> for Cow<'_, T>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2161:22
         |
    2161 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2161 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2161 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2300:22
         |
    2300 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2300 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2300 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2501:18
         |
    2501 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2501 -             impl<'de> Visitor<'de> for FieldVisitor {
    2501 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2658:18
         |
    2658 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2658 -             impl<'de> Visitor<'de> for FieldVisitor {
    2658 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2796:18
         |
    2796 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2796 -             impl<'de> Visitor<'de> for FieldVisitor {
    2796 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2907:22
         |
    2907 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2907 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2907 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:3018:22
         |
    3018 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    3018 -                 impl<'de> Visitor<'de> for FieldVisitor {
    3018 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:3166:6
         |
    3166 | impl<'de, T> Visitor<'de> for FromStrVisitor<T>
         |      ^^^             ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    3166 - impl<'de, T> Visitor<'de> for FromStrVisitor<T>
    3166 + impl<T> Visitor<'_> for FromStrVisitor<T>
         |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/mod.rs:397:6
        |
    397 | impl<'a> fmt::Display for Unexpected<'a> {
        |      ^^                              ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    397 - impl<'a> fmt::Display for Unexpected<'a> {
    397 + impl fmt::Display for Unexpected<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'f, 'a
        --> serde/src/de/mod.rs:2309:14
         |
    2309 |         impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
         |              ^^  ^^                                     ^^  ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2309 -         impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
    2309 +         impl fmt::Write for LookForDecimalPoint<'_, '_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/ser/fmt.rs:38:6
       |
    38 | impl<'a> Serializer for &mut fmt::Formatter<'a> {
       |      ^^                                     ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
       |
    38 - impl<'a> Serializer for &mut fmt::Formatter<'a> {
    38 + impl Serializer for &mut fmt::Formatter<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/ser/impls.rs:62:6
       |
    62 | impl<'a> Serialize for fmt::Arguments<'a> {
       |      ^^                               ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
       |
    62 - impl<'a> Serialize for fmt::Arguments<'a> {
    62 + impl Serialize for fmt::Arguments<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/format.rs:20:6
       |
    20 | impl<'a> Write for Buf<'a> {
       |      ^^                ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
       |
    20 - impl<'a> Write for Buf<'a> {
    20 + impl Write for Buf<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:254:10
        |
    254 |     impl<'de> Content<'de> {
        |          ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    254 -     impl<'de> Content<'de> {
    254 +     impl Content<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:333:10
        |
    333 |     impl<'de> ContentVisitor<'de> {
        |          ^^^                 ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    333 -     impl<'de> ContentVisitor<'de> {
    333 +     impl ContentVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:553:10
        |
    553 |     impl<'de> TagOrContentVisitor<'de> {
        |          ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    553 -     impl<'de> TagOrContentVisitor<'de> {
    553 +     impl TagOrContentVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:937:10
        |
    937 |     impl<'de> Visitor<'de> for TagOrContentFieldVisitor {
        |          ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
        |
    937 -     impl<'de> Visitor<'de> for TagOrContentFieldVisitor {
    937 +     impl Visitor<'_> for TagOrContentFieldVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/private/de.rs:1014:10
         |
    1014 |     impl<'de> Visitor<'de> for TagContentOtherFieldVisitor {
         |          ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1014 -     impl<'de> Visitor<'de> for TagContentOtherFieldVisitor {
    1014 +     impl Visitor<'_> for TagContentOtherFieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:1652:10
         |
    1652 |     impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
         |          ^^                                 ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1652 -     impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
    1652 +     impl<'de, E> ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:1735:15
         |
    1735 |     impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
         |               ^^                                                  ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    1735 -     impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
    1735 +     impl<'de, E> Deserializer<'de> for ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2162:15
         |
    2162 |     impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
         |               ^^                                                       ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2162 -     impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
    2162 +     impl<'de, E> de::VariantAccess<'de> for VariantRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2259:15
         |
    2259 |     impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
         |               ^^                                                             ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2259 -     impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
    2259 +     impl<'de, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2288:15
         |
    2288 |     impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> {
         |               ^^                                               ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2288 -     impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> {
    2288 +     impl<'de> Visitor<'de> for InternallyTaggedUnitVisitor<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'de, 'a
        --> serde/src/private/de.rs:2333:10
         |
    2333 |     impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> {
         |          ^^^  ^^          ^^^                          ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2333 -     impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> {
    2333 +     impl Visitor<'_> for UntaggedUnitVisitor<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2396:11
         |
    2396 | impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
         |           ^^                                           ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2396 - impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
    2396 + impl<'de, E> Deserializer<'de> for StrDeserializer<'_, E>
         |

    warning: the following explicit lifetimes could be elided: 'a, 'de
        --> serde/src/private/de.rs:2498:6
         |
    2498 | impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
         |      ^^  ^^^                         ^^  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2498 - impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
    2498 + impl<E> FlatMapDeserializer<'_, '_, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2522:6
         |
    2522 | impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
         |      ^^                                                    ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2522 - impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
    2522 + impl<'de, E> Deserializer<'de> for FlatMapDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2658:6
         |
    2658 | impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
         |      ^^                                           ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2658 - impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
    2658 + impl<'de, E> MapAccess<'de> for FlatMapAccess<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2702:6
         |
    2702 | impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
         |      ^^                                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    2702 - impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
    2702 + impl<'de, E> MapAccess<'de> for FlatStructAccess<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
     --> serde/src/de/seed.rs:8:6
      |
    8 | impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
      |      ^^                                               ^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
      |
    8 - impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
    8 + impl<'de, T> DeserializeSeed<'de> for InPlaceSeed<'_, T>
      |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde_derive/src/internals/case.rs:124:6
        |
    124 | impl<'a> Display for ParseError<'a> {
        |      ^^                         ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
        = note: `-W clippy::elidable-lifetime-names` implied by `-W clippy::pedantic`
        = help: to override `-W clippy::pedantic` add `#[allow(clippy::elidable_lifetime_names)]`
    help: elide the lifetimes
        |
    124 - impl<'a> Display for ParseError<'a> {
    124 + impl Display for ParseError<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde_derive/src/de.rs:3109:6
         |
    3109 | impl<'a> ToTokens for DeImplGenerics<'a> {
         |      ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    3109 - impl<'a> ToTokens for DeImplGenerics<'a> {
    3109 + impl ToTokens for DeImplGenerics<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde_derive/src/de.rs:3191:6
         |
    3191 | impl<'a> ToTokens for DeTypeGenerics<'a> {
         |      ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
    help: elide the lifetimes
         |
    3191 - impl<'a> ToTokens for DeTypeGenerics<'a> {
    3191 + impl ToTokens for DeTypeGenerics<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
      --> test_suite/tests/test_serde_path.rs:16:10
       |
    16 |     impl<'a> AssertNotSerdeDeserialize<'a> for Foo {}
       |          ^^                            ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names
       = note: `-W clippy::elidable-lifetime-names` implied by `-W clippy::pedantic`
       = help: to override `-W clippy::pedantic` add `#[allow(clippy::elidable_lifetime_names)]`
    help: elide the lifetimes
       |
    16 -     impl<'a> AssertNotSerdeDeserialize<'a> for Foo {}
    16 +     impl AssertNotSerdeDeserialize<'_> for Foo {}
       |
2025-03-03 00:00:21 -08:00
David Tolnay e3eaa6a3dd Merge pull request #2896 from dtolnay/stabledoc
Also link to stable proc_macro
2025-02-20 05:30:47 +00:00
David Tolnay 6a630cf283 Also link to stable proc_macro 2025-02-19 21:26:32 -08:00
David Tolnay 7bfd518dd4 Release 1.0.218 2025-02-19 21:20:03 -08:00
David Tolnay 723a9491e2 Merge pull request #2895 from dtolnay/stabledoc
Point standard library links to stable
2025-02-20 05:14:52 +00:00
David Tolnay 2b44efb085 Point standard library links to stable 2025-02-19 21:08:50 -08:00
David Tolnay 03dc0fc137 Merge pull request #2894 from dtolnay/doclink
Convert html links to intra-doc links
2025-02-20 05:01:07 +00:00
David Tolnay 85cb0c478e Convert html links to intra-doc links 2025-02-19 20:51:41 -08:00
David Tolnay abe7194480 Update ui test suite to nightly-2025-02-12 2025-02-11 18:19:51 -08:00
David Tolnay aaccac7413 Unset doc-scrape-examples for lib target
False is the default value since Cargo PR 11499.
2025-02-09 17:52:36 -08:00
David Tolnay 7cd4d84cac Update ui test suite to nightly-2025-02-07 2025-02-06 19:35:51 -08:00
David Tolnay 04ff3e8f95 More precise gitignore patterns 2025-01-23 01:41:05 -08:00
David Tolnay dc3031b614 Remove *.sw[po] from gitignore
This belongs in someone's global gitignore.
2025-01-22 19:36:55 -08:00
David Tolnay 1e2f931d0c Remove **/*.rs.bk from project-specific gitignore
Cargo stopped generating this in its project template 5 years ago. It
would belong in a global gitignore instead.
2025-01-22 19:30:32 -08:00
David Tolnay 930401b0dd Release 1.0.217 2024-12-27 12:41:22 -08:00
Mingun cb6eaea151 Fix roundtrip inconsistency:
- deserialization of flatten unit variant is possible
- serialization of such variant gives Err("can only flatten structs and maps (got an enum)")
2024-12-27 08:21:07 +00:00
David Tolnay b6f339ca36 Resolve repr_packed_without_abi clippy lint in tests
warning: item uses `packed` representation without ABI-qualification
       --> test_suite/tests/test_gen.rs:774:5
        |
    772 |       #[repr(packed)]
        |              ------ `packed` representation set here
    773 |       #[allow(dead_code)]
    774 | /     struct Packed {
    775 | |         x: u8,
    776 | |         y: u16,
    777 | |     }
        | |_____^
        |
        = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
        = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[warn(clippy::repr_packed_without_abi)]` implied by `#[warn(warnings)]`

    warning: item uses `packed` representation without ABI-qualification
       --> test_suite/tests/test_gen.rs:919:1
        |
    918 |   #[repr(packed)]
        |          ------ `packed` representation set here
    919 | / pub struct RemotePacked {
    920 | |     pub a: u16,
    921 | |     pub b: u32,
    922 | | }
        | |_^
        |
        = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
        = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi

    warning: item uses `packed` representation without ABI-qualification
       --> test_suite/tests/test_gen.rs:927:1
        |
    925 |   #[repr(packed)]
        |          ------ `packed` representation set here
    926 |   #[serde(remote = "RemotePacked")]
    927 | / pub struct RemotePackedDef {
    928 | |     a: u16,
    929 | |     b: u32,
    930 | | }
        | |_^
        |
        = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
        = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi

    warning: item uses `packed` representation without ABI-qualification
       --> test_suite/tests/test_gen.rs:937:1
        |
    936 |   #[repr(packed)]
        |          ------ `packed` representation set here
    937 | / pub struct RemotePackedNonCopy {
    938 | |     pub a: u16,
    939 | |     pub b: String,
    940 | | }
        | |_^
        |
        = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
        = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi

    warning: item uses `packed` representation without ABI-qualification
       --> test_suite/tests/test_gen.rs:945:1
        |
    943 |   #[repr(packed)]
        |          ------ `packed` representation set here
    944 |   #[serde(remote = "RemotePackedNonCopy")]
    945 | / pub struct RemotePackedNonCopyDef {
    946 | |     a: u16,
    947 | |     b: String,
    948 | | }
        | |_^
        |
        = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
        = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi
2024-12-26 18:33:33 -08:00
David Tolnay 2a5caea1a8 Merge pull request #2872 from dtolnay/ehpersonality
Drop #[lang = "eh_personality"] from no-std test
2024-12-20 04:33:24 -08:00
David Tolnay b9f93f99aa Add no-std CI on stable compiler 2024-12-20 04:30:14 -08:00
David Tolnay eb5cd476ba Drop #[lang = "eh_personality"] from no-std test 2024-12-20 04:28:35 -08:00
David Tolnay 8478a3b7dd Merge pull request #2871 from dtolnay/nostdstart
Replace #[start] with extern fn main
2024-12-20 04:28:27 -08:00
David Tolnay dbb909136e Replace #[start] with extern fn main 2024-12-20 04:20:26 -08:00
David Tolnay ad8dd4148b Release 1.0.216 2024-12-10 18:05:39 -08:00
David Tolnay f91d2ed9ae Merge pull request #2868 from dtolnay/automaticallyderived
Mark all generated trait impls as #[automatically_derived]
2024-12-10 18:04:42 -08:00
David Tolnay 9497463718 Mark all generated trait impls as #[automatically_derived] 2024-12-10 17:57:05 -08:00
Oli Scherer 46e9ecfcdd Merge pull request #2866 from tdittr/mark-visitors-as-generated
Mark generated `impl de::Visitor` blocks as `#[automatically_derived]`
2024-12-09 11:58:24 +01:00
Tamme Dittrich e9c399c822 Mark generated impl de::Visitor blocks as #[automatically_derived]
This hides the generated visitors and field visitors from code
coverage.
2024-12-05 17:26:13 +01:00
David Tolnay b9dbfcb4ac Switch out fnv in favor of foldhash in test 2024-11-16 12:24:05 -08:00
David Tolnay c270e27a4d Use BuildHasher instead of Hasher in collection macros 2024-11-16 12:23:34 -08:00
David Tolnay 0307f604ea Resolve question_mark clippy lint in build script
warning: this `match` expression can be replaced with `?`
       --> serde/build.rs:111:17
        |
    111 |       let rustc = match env::var_os("RUSTC") {
        |  _________________^
    112 | |         Some(rustc) => rustc,
    113 | |         None => return None,
    114 | |     };
        | |_____^ help: try instead: `env::var_os("RUSTC")?`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
        = note: `-W clippy::question-mark` implied by `-W clippy::all`
        = help: to override `-W clippy::all` add `#[allow(clippy::question_mark)]`

    warning: this `match` expression can be replaced with `?`
       --> serde/build.rs:131:16
        |
    131 |       let next = match pieces.next() {
        |  ________________^
    132 | |         Some(next) => next,
    133 | |         None => return None,
    134 | |     };
        | |_____^ help: try instead: `pieces.next()?`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
2024-11-15 18:57:00 -08:00
David Tolnay 8939af48fe Release 1.0.215 2024-11-11 13:03:35 -08:00
David Tolnay fa5d58cd00 Use ui test syntax that does not interfere with rustfmt 2024-11-10 23:50:37 -08:00
David Tolnay 1a3cf4b3c1 Update PR 2562 ui tests 2024-11-10 23:46:31 -08:00
David Tolnay 7d96352e96 Merge pull request #2857 from dtolnay/collide
Revert the colliding aliases hard error (PRs #2562 & #2853)
2024-11-10 23:37:01 -08:00
David Tolnay 111ecc5d8c Update ui tests for warning on colliding aliases 2024-11-10 23:31:55 -08:00
David Tolnay edd6fe954b Revert "Add checks for conflicts for aliases"
This reverts commit 5f9fffa53e.
2024-11-10 23:31:55 -08:00
David Tolnay a20e9249c5 Revert "pacify clippy"
This reverts commit 951ca5ace0.
2024-11-10 23:31:55 -08:00
David Tolnay b1353a99cd Merge pull request #2856 from dtolnay/dename
Produce a separate warning for every colliding name
2024-11-10 23:31:44 -08:00
David Tolnay c59e876bb3 Produce a separate warning for every colliding name 2024-11-10 23:23:09 -08:00
David Tolnay 7f1e697c0d Merge pull request #2855 from dtolnay/namespan
Produce unreachable_patterns warning when deserialization names collide
2024-11-10 23:21:46 -08:00
David Tolnay 373edcd055 Keep track of a span for alias strings 2024-11-10 23:08:40 -08:00
David Tolnay f0b5c4f857 Move MultiName to a new module 2024-11-10 22:32:49 -08:00
David Tolnay 3035d4fa34 Rename Name -> MultiName 2024-11-10 22:32:49 -08:00
David Tolnay 60ac737439 Prevent upload-artifact step from causing CI failure
This step has been failing way more than reasonable across my various repos.

    With the provided path, there will be 1 file uploaded
    Artifact name is valid!
    Root directory input is valid!
    Attempt 1 of 5 failed with error: Request timeout: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact. Retrying request in 3000 ms...
    Attempt 2 of 5 failed with error: Request timeout: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact. Retrying request in 6029 ms...
    Attempt 3 of 5 failed with error: Request timeout: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact. Retrying request in 8270 ms...
    Attempt 4 of 5 failed with error: Request timeout: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact. Retrying request in 12577 ms...
    Error: Failed to CreateArtifact: Failed to make request after 5 attempts: Request timeout: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact
2024-11-08 21:45:52 -05:00
Oli Scherer a95b0d301e Merge pull request #2853 from serde-rs/oli-obk-patch-1
pacify clippy
2024-11-01 15:25:08 +01:00
Oli Scherer 951ca5ace0 pacify clippy 2024-11-01 15:20:51 +01:00
Oli Scherer adf05a5bf6 Merge pull request #2562 from Mingun/alias-check
Add checks for conflicts for aliases
2024-11-01 15:14:15 +01:00
David Tolnay 418062165f Release 1.0.214 2024-10-28 09:41:44 -07:00
David Tolnay 210373b3b6 Merge pull request #2568 from Mingun/into_deserializer-for-deserializers
Implement `IntoDeserializer` for all `Deserializer`s in `serde::de::value` module
2024-10-28 09:40:57 -07:00
Mingun 5f9fffa53e Add checks for conflicts for aliases
- Check that alias is not the same as name of other field (it still can be the name of owning field/variant)
- Check that aliases are unique, i. e. two different fields does not use the same alias
2024-10-25 19:18:31 +05:00
Mingun 9cda015733 Implement IntoDeserializer for all Deserializers in serde::de::value module
Unfortunately, blanket implementation IntoDeserializer for Deserializer is impossible
right now because this would be a breaking change. External crates may have this
such implementation (and serde_json actually have it for Value)
2024-10-25 19:17:50 +05:00
David Tolnay 58a8d22931 Release 1.0.213 2024-10-22 11:14:58 -07:00
David Tolnay ef0ed22593 Merge pull request #2847 from dtolnay/newtypewith
Hygiene for macro-generated newtype struct deserialization with `with` attr
2024-10-22 11:14:18 -07:00
David Tolnay 79925ac394 Ignore dead_code warning in regression test
warning: field `0` is never read
      --> test_suite/tests/regression/issue2846.rs:8:45
       |
    8  |         pub struct S(#[serde(with = $with)] i32);
       |                    - field in this struct   ^^^
    ...
    12 | declare_in_macro!("with");
       | ------------------------- in this macro invocation
       |
       = help: consider removing this field
       = note: `#[warn(dead_code)]` on by default
       = note: this warning originates in the macro `declare_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
2024-10-22 11:10:52 -07:00
David Tolnay b60e4092ec Hygiene for macro-generated newtype struct deserialization with 'with' attr 2024-10-22 11:10:40 -07:00
David Tolnay fdc36e5c06 Add regression test for issue 2846
error[E0425]: cannot find value `__e` in this scope
      --> test_suite/tests/regression/issue2846.rs:12:19
       |
    12 | declare_in_macro!("with");
       |                   ^^^^^^ not found in this scope
2024-10-22 11:08:22 -07:00
David Tolnay 49e11ce1ba Ignore trivially_copy_pass_by_ref pedantic clippy lint in test
warning: this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
      --> test_suite/tests/regression/issue2844.rs:18:28
       |
    18 |     pub fn serialize<S>(_: &i32, _: S) -> Result<S::Ok, S::Error>
       |                            ^^^^ help: consider passing by value instead: `i32`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
       = note: `-W clippy::trivially-copy-pass-by-ref` implied by `-W clippy::pedantic`
       = help: to override `-W clippy::pedantic` add `#[allow(clippy::trivially_copy_pass_by_ref)]`
2024-10-22 09:56:12 -07:00
David Tolnay 7ae1b5f8f3 Release 1.0.212 2024-10-22 09:41:55 -07:00
David Tolnay 1ac054b34a Merge pull request #2845 from dtolnay/withlocal
Fix hygiene of macro-generated local variable accesses in serde(with) wrappers
2024-10-22 09:41:27 -07:00
David Tolnay 1e36ef551d Fix hygiene of macro-generated local variable accesses in serde(with) wrappers 2024-10-22 09:38:06 -07:00
David Tolnay 0058c7226e Add regression test for issue 2844
error[E0424]: expected value, found module `self`
      --> test_suite/tests/regression/issue2844.rs:13:19
       |
    5  |         #[derive(Serialize, Deserialize)]
       |                  --------- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
    ...
    13 | declare_in_macro!("with");
       |                   ^^^^^^ `self` value is a keyword only available in methods with a `self` parameter

    error[E0425]: cannot find value `__s` in this scope
      --> test_suite/tests/regression/issue2844.rs:13:19
       |
    13 | declare_in_macro!("with");
       |                   ^^^^^^ not found in this scope

    error[E0425]: cannot find value `__deserializer` in this scope
      --> test_suite/tests/regression/issue2844.rs:13:19
       |
    13 | declare_in_macro!("with");
       |                   ^^^^^^ not found in this scope
2024-10-22 09:37:58 -07:00
David Tolnay 29d4f3e887 Format regression tests with rustfmt 2024-10-22 09:28:10 -07:00
David Tolnay 1b8310d98a Release 1.0.211 2024-10-21 23:27:57 -07:00
David Tolnay af4c388dff Merge pull request #2843 from dtolnay/fieldwithaliases
Collect field ident and aliases into a struct
2024-10-21 23:23:28 -07:00
David Tolnay 09f6d9361d Collect field ident and aliases into a struct 2024-10-21 23:16:05 -07:00
David Tolnay 1f9eb8300f Merge pull request #2842 from dtolnay/identsaliases
Rename field_names_idents -> field_idents_aliases
2024-10-21 23:13:23 -07:00
David Tolnay c6a5be7f6a Rename variant_names_idents -> variant_idents_aliases 2024-10-21 22:56:07 -07:00
David Tolnay 0a06af8d21 Rename field_names_idents -> field_idents_aliases 2024-10-21 22:48:02 -07:00
David Tolnay 3393ad6760 Make most of prepare_enum_variant_enum independent of variant_names_idents item type 2024-10-21 22:47:42 -07:00
David Tolnay 830309fcb5 Merge pull request #2841 from dtolnay/serializewith
Reduce scope of quote_spanned on SerializeWith wrapper
2024-10-21 21:56:51 -07:00
David Tolnay ab4f3f3111 Reduce scope of quote_spanned on SerializeWith wrapper 2024-10-21 21:09:18 -07:00
David Tolnay 00460b8dee Fix wording in comments from PR 2558 2024-10-21 21:07:13 -07:00
David Tolnay d4486be2b9 Format all ui tests from PR 2558 using rustfmt 2024-10-21 19:43:45 -07:00
David Tolnay 991e344804 Raise required compiler for serde_derive to 1.61
This is the rust-version declared by recent versions of Syn.
2024-10-21 19:30:51 -07:00
David Tolnay 6a7de26e5a Ignore uninlined_format_args pedantic clippy lint
warning: variables can be used directly in the `format!` string
       --> serde_derive/src/internals/attr.rs:546:36
        |
    546 |                         meta.error(format_args!("unknown serde container attribute `{}`", path))
        |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
        = note: `-W clippy::uninlined-format-args` implied by `-W clippy::pedantic`
        = help: to override `-W clippy::pedantic` add `#[allow(clippy::uninlined_format_args)]`
    help: change this to
        |
    546 -                         meta.error(format_args!("unknown serde container attribute `{}`", path))
    546 +                         meta.error(format_args!("unknown serde container attribute `{path}`"))
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/internals/attr.rs:940:36
        |
    940 |                         meta.error(format_args!("unknown serde variant attribute `{}`", path))
        |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    940 -                         meta.error(format_args!("unknown serde variant attribute `{}`", path))
    940 +                         meta.error(format_args!("unknown serde variant attribute `{path}`"))
        |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1095:33
         |
    1095 | ...                   format!("field `{}` does not have lifetime {}", ident, lifetime);
         |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1095 -                                 format!("field `{}` does not have lifetime {}", ident, lifetime);
    1095 +                                 format!("field `{ident}` does not have lifetime {lifetime}");
         |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1196:47
         |
    1196 |   ...                   let msg = format!(
         |  _________________________________^
    1197 | | ...                       "field `{}` does not have lifetime {}",
    1198 | | ...                       ident, lifetime,
    1199 | | ...                   );
         | |_______________________^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1222:36
         |
    1222 |                         meta.error(format_args!("unknown serde field attribute `{}`", path))
         |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1222 -                         meta.error(format_args!("unknown serde field attribute `{}`", path))
    1222 +                         meta.error(format_args!("unknown serde field attribute `{path}`"))
         |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1415:39
         |
    1415 |                   return Err(meta.error(format_args!(
         |  _______________________________________^
    1416 | |                     "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`",
    1417 | |                     attr_name,
    1418 | |                 )));
         | |_________________^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1482:17
         |
    1482 |                 format!("unexpected suffix `{}` on string literal", suffix),
         |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1482 -                 format!("unexpected suffix `{}` on string literal", suffix),
    1482 +                 format!("unexpected suffix `{suffix}` on string literal"),
         |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1489:13
         |
    1489 | /             format!(
    1490 | |                 "expected serde {} attribute to be a string: `{} = \"...\"`",
    1491 | |                 attr_name, meta_item_name
    1492 | |             ),
         | |_____________^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1604:21
         |
    1604 |                     format!("duplicate borrowed lifetime `{}`", lifetime),
         |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1604 -                     format!("duplicate borrowed lifetime `{}`", lifetime),
    1604 +                     format!("duplicate borrowed lifetime `{lifetime}`"),
         |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/internals/attr.rs:1778:19
         |
    1778 |         let msg = format!("field `{}` has no lifetimes to borrow", name);
         |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1778 -         let msg = format!("field `{}` has no lifetimes to borrow", name);
    1778 +         let msg = format!("field `{name}` has no lifetimes to borrow");
         |

    warning: variables can be used directly in the `format!` string
      --> serde_derive/src/internals/check.rs:41:29
       |
    41 | ...   format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
       |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
       |
    41 -                             format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
    41 +                             format!("field must have #[serde(default)] because previous field {first} has #[serde(default)]"),
       |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/internals/check.rs:314:13
        |
    314 |             format!("variant field name `{}` conflicts with internal tag", tag),
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    314 -             format!("variant field name `{}` conflicts with internal tag", tag),
    314 +             format!("variant field name `{tag}` conflicts with internal tag"),
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/internals/check.rs:361:13
        |
    361 | /             format!(
    362 | |                 "enum tags `{}` for type and content conflict with each other",
    363 | |                 type_tag
    364 | |             ),
        | |_____________^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/internals/check.rs:450:33
        |
    450 |         Member::Named(ident) => format!("`{}`", ident),
        |                                 ^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    450 -         Member::Named(ident) => format!("`{}`", ident),
    450 +         Member::Named(ident) => format!("`{ident}`"),
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/de.rs:697:9
        |
    697 |         format!("{} with 1 element", expecting)
        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    697 -         format!("{} with 1 element", expecting)
    697 +         format!("{expecting} with 1 element")
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/de.rs:699:9
        |
    699 |         format!("{} with {} elements", expecting, deserialized_count)
        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    699 -         format!("{} with {} elements", expecting, deserialized_count)
    699 +         format!("{expecting} with {deserialized_count} elements")
        |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/de.rs:1442:21
         |
    1442 |     let expecting = format!("adjacently tagged enum {}", rust_name);
         |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1442 -     let expecting = format!("adjacently tagged enum {}", rust_name);
    1442 +     let expecting = format!("adjacently tagged enum {rust_name}");
         |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/de.rs:2842:17
         |
    2842 |     Ident::new(&format!("__field{}", i), Span::call_site())
         |                 ^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    2842 -     Ident::new(&format!("__field{}", i), Span::call_site())
    2842 +     Ident::new(&format!("__field{i}"), Span::call_site())
         |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/ser.rs:457:42
        |
    457 |                     .map(|i| Ident::new(&format!("__field{}", i), Span::call_site()));
        |                                          ^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    457 -                     .map(|i| Ident::new(&format!("__field{}", i), Span::call_site()));
    457 +                     .map(|i| Ident::new(&format!("__field{i}"), Span::call_site()));
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/ser.rs:714:48
        |
    714 |             .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site())))
        |                                                ^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    714 -             .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site())))
    714 +             .map(|i| Member::Named(Ident::new(&format!("__field{i}"), Span::call_site())))
        |

    warning: variables can be used directly in the `format!` string
       --> serde_derive/src/ser.rs:832:46
        |
    832 |                 let field_expr = Ident::new(&format!("__field{}", i), Span::call_site());
        |                                              ^^^^^^^^^^^^^^^^^^^^^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
        |
    832 -                 let field_expr = Ident::new(&format!("__field{}", i), Span::call_site());
    832 +                 let field_expr = Ident::new(&format!("__field{i}"), Span::call_site());
        |

    warning: variables can be used directly in the `format!` string
        --> serde_derive/src/ser.rs:1062:38
         |
    1062 |                 let id = Ident::new(&format!("__field{}", i), Span::call_site());
         |                                      ^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
    help: change this to
         |
    1062 -                 let id = Ident::new(&format!("__field{}", i), Span::call_site());
    1062 +                 let id = Ident::new(&format!("__field{i}"), Span::call_site());
         |
2024-10-21 19:30:51 -07:00
David Tolnay 5382ef3b0b Merge pull request #2840 from dtolnay/needlesslifetimes
Ignore needless_lifetimes clippy lint in generated code
2024-10-21 19:25:40 -07:00
David Tolnay a8cbc9184e Ignore needless_lifetimes clippy lint in generated code 2024-10-21 19:12:52 -07:00
David Tolnay 966e9ccf0c Merge pull request #2839 from dtolnay/pr2558
Update ui tests from PR 2558
2024-10-21 18:58:21 -07:00
David Tolnay 53ade10137 Update ui tests from PR 2558 2024-10-21 18:52:49 -07:00
David Tolnay 422c719352 Temporarily disable 1.56 CI
While fixing other errors from recently merged PRs.
2024-10-21 18:47:54 -07:00
Oli Scherer 3415619bfd Merge pull request #2566 from Mingun/variant-aliases
Show variant aliases in error message
2024-10-21 21:40:57 +02:00
Oli Scherer 04bb76bc00 Merge pull request #2558 from Mingun/correct-span
Improve error reporting about mismatched signature in `with` and `default` attributes
2024-10-21 21:38:09 +02:00
David Tolnay 8b0f482666 Update for precise capture bounds
warning: some variants are not matched explicitly
       --> serde_derive/src/internals/receiver.rs:209:15
        |
    209 |         match bound {
        |               ^^^^^ pattern `&mut TypeParamBound::PreciseCapture(_)` not covered
        |
        = help: ensure that all variants are matched explicitly by adding the suggested match arms
        = note: the matched value is of type `&mut TypeParamBound` and the `non_exhaustive_omitted_patterns` attribute was found
    note: the lint level is defined here
       --> serde_derive/src/internals/receiver.rs:210:53
        |
    210 |             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    warning: some variants are not matched explicitly
       --> serde_derive/src/bound.rs:227:19
        |
    227 |             match bound {
        |                   ^^^^^ pattern `&TypeParamBound::PreciseCapture(_)` not covered
        |
        = help: ensure that all variants are matched explicitly by adding the suggested match arms
        = note: the matched value is of type `&TypeParamBound` and the `non_exhaustive_omitted_patterns` attribute was found
    note: the lint level is defined here
       --> serde_derive/src/bound.rs:228:57
        |
    228 |                 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
        |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-20 20:35:48 -07:00
David Tolnay 4b3178b053 Ignore needless_lifetimes clippy lint
warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:124:6
        |
    124 | impl<'de, E> IntoDeserializer<'de, E> for ()
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
        = note: `-W clippy::needless-lifetimes` implied by `-W clippy::all`
        = help: to override `-W clippy::all` add `#[allow(clippy::needless_lifetimes)]`
    help: elide the lifetimes
        |
    124 - impl<'de, E> IntoDeserializer<'de, E> for ()
    124 + impl<E> IntoDeserializer<'_, E> for ()
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:196:6
        |
    196 | impl<'de, E> IntoDeserializer<'de, E> for !
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    196 - impl<'de, E> IntoDeserializer<'de, E> for !
    196 + impl<E> IntoDeserializer<'_, E> for !
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:317:6
        |
    317 | impl<'de, E> IntoDeserializer<'de, E> for u32
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    317 - impl<'de, E> IntoDeserializer<'de, E> for u32
    317 + impl<E> IntoDeserializer<'_, E> for u32
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:406:6
        |
    406 | impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    406 - impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str
    406 + impl<'a, E> IntoDeserializer<'_, E> for &'a str
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:427:11
        |
    427 | impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E>
        |           ^^                                               ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    427 - impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E>
    427 + impl<'de, E> de::Deserializer<'de> for StrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:461:11
        |
    461 | impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
        |           ^^                                             ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    461 - impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
    461 + impl<'de, E> de::EnumAccess<'de> for StrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:476:6
        |
    476 | impl<'a, E> Debug for StrDeserializer<'a, E> {
        |      ^^                               ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    476 - impl<'a, E> Debug for StrDeserializer<'a, E> {
    476 + impl<E> Debug for StrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:555:6
        |
    555 | impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
        |      ^^^                                       ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    555 - impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
    555 + impl<E> Debug for BorrowedStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:586:6
        |
    586 | impl<'de, E> IntoDeserializer<'de, E> for String
        |      ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    586 - impl<'de, E> IntoDeserializer<'de, E> for String
    586 + impl<E> IntoDeserializer<'_, E> for String
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:680:6
        |
    680 | impl<'a, E> Clone for CowStrDeserializer<'a, E> {
        |      ^^                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    680 - impl<'a, E> Clone for CowStrDeserializer<'a, E> {
    680 + impl<E> Clone for CowStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:691:6
        |
    691 | impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    691 - impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
    691 + impl<'a, E> IntoDeserializer<'_, E> for Cow<'a, str>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:714:11
        |
    714 | impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
        |           ^^                                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    714 - impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
    714 + impl<'de, E> de::Deserializer<'de> for CowStrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:752:11
        |
    752 | impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
        |           ^^                                                ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    752 - impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
    752 + impl<'de, E> de::EnumAccess<'de> for CowStrDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:768:6
        |
    768 | impl<'a, E> Debug for CowStrDeserializer<'a, E> {
        |      ^^                                  ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    768 - impl<'a, E> Debug for CowStrDeserializer<'a, E> {
    768 + impl<E> Debug for CowStrDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:797:6
        |
    797 | impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
        |      ^^^                          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    797 - impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
    797 + impl<'a, E> IntoDeserializer<'_, E> for &'a [u8]
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:808:11
        |
    808 | impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
        |           ^^                                             ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    808 - impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
    808 + impl<'de, E> Deserializer<'de> for BytesDeserializer<'_, E>
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/value.rs:828:6
        |
    828 | impl<'a, E> Debug for BytesDeserializer<'a, E> {
        |      ^^                                 ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    828 - impl<'a, E> Debug for BytesDeserializer<'a, E> {
    828 + impl<E> Debug for BytesDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/value.rs:876:6
        |
    876 | impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
        |      ^^^                                         ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    876 - impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
    876 + impl<E> Debug for BorrowedBytesDeserializer<'_, E> {
        |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1101:6
         |
    1101 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1101 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1101 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1118:6
         |
    1118 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1118 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1118 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1141:6
         |
    1141 | impl<'de, I, E> MapDeserializer<'de, I, E>
         |      ^^^                        ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1141 - impl<'de, I, E> MapDeserializer<'de, I, E>
    1141 + impl<I, E> MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1287:6
         |
    1287 | impl<'de, I, E> Clone for MapDeserializer<'de, I, E>
         |      ^^^                                  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1287 - impl<'de, I, E> Clone for MapDeserializer<'de, I, E>
    1287 + impl<I, E> Clone for MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/value.rs:1304:6
         |
    1304 | impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
         |      ^^^                                  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1304 - impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
    1304 + impl<I, E> Debug for MapDeserializer<'_, I, E>
         |

    warning: the following explicit lifetimes could be elided: 'de
      --> serde/src/de/impls.rs:17:6
       |
    17 | impl<'de> Visitor<'de> for UnitVisitor {
       |      ^^^          ^^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    17 - impl<'de> Visitor<'de> for UnitVisitor {
    17 + impl Visitor<'_> for UnitVisitor {
       |

    warning: the following explicit lifetimes could be elided: 'de
      --> serde/src/de/impls.rs:56:6
       |
    56 | impl<'de> Visitor<'de> for BoolVisitor {
       |      ^^^          ^^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    56 - impl<'de> Visitor<'de> for BoolVisitor {
    56 + impl Visitor<'_> for BoolVisitor {
       |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:550:6
        |
    550 | impl<'de> Visitor<'de> for CharVisitor {
        |      ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    550 - impl<'de> Visitor<'de> for CharVisitor {
    550 + impl Visitor<'_> for CharVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:596:6
        |
    596 | impl<'de> Visitor<'de> for StringVisitor {
        |      ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    596 - impl<'de> Visitor<'de> for StringVisitor {
    596 + impl Visitor<'_> for StringVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'de, 'a
       --> serde/src/de/impls.rs:642:6
        |
    642 | impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
        |      ^^  ^^^          ^^^                           ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    642 - impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
    642 + impl Visitor<'_> for StringInPlaceVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/de/impls.rs:953:6
        |
    953 | impl<'de, T> Visitor<'de> for PhantomDataVisitor<T>
        |      ^^^             ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    953 - impl<'de, T> Visitor<'de> for PhantomDataVisitor<T>
    953 + impl<T> Visitor<'_> for PhantomDataVisitor<T>
        |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/impls.rs:1195:14
         |
    1195 |         impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T>
         |              ^^                                             ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1195 -         impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T>
    1195 +         impl<'de, T> Visitor<'de> for VecInPlaceVisitor<'_, T>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:1838:6
         |
    1838 | impl<'de> Visitor<'de> for PathBufVisitor {
         |      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1838 - impl<'de> Visitor<'de> for PathBufVisitor {
    1838 + impl Visitor<'_> for PathBufVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/impls.rs:1991:11
         |
    1991 | impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T>
         |           ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1991 - impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T>
    1991 + impl<'de, T> Deserialize<'de> for Cow<'_, T>
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2161:22
         |
    2161 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2161 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2161 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2300:22
         |
    2300 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2300 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2300 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2501:18
         |
    2501 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2501 -             impl<'de> Visitor<'de> for FieldVisitor {
    2501 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2658:18
         |
    2658 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2658 -             impl<'de> Visitor<'de> for FieldVisitor {
    2658 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2796:18
         |
    2796 |             impl<'de> Visitor<'de> for FieldVisitor {
         |                  ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2796 -             impl<'de> Visitor<'de> for FieldVisitor {
    2796 +             impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:2907:22
         |
    2907 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2907 -                 impl<'de> Visitor<'de> for FieldVisitor {
    2907 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:3018:22
         |
    3018 |                 impl<'de> Visitor<'de> for FieldVisitor {
         |                      ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    3018 -                 impl<'de> Visitor<'de> for FieldVisitor {
    3018 +                 impl Visitor<'_> for FieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/de/impls.rs:3166:6
         |
    3166 | impl<'de, T> Visitor<'de> for FromStrVisitor<T>
         |      ^^^             ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    3166 - impl<'de, T> Visitor<'de> for FromStrVisitor<T>
    3166 + impl<T> Visitor<'_> for FromStrVisitor<T>
         |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/mod.rs:397:6
        |
    397 | impl<'a> fmt::Display for Unexpected<'a> {
        |      ^^                              ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    397 - impl<'a> fmt::Display for Unexpected<'a> {
    397 + impl fmt::Display for Unexpected<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'f, 'a
        --> serde/src/de/mod.rs:2309:14
         |
    2309 |         impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
         |              ^^  ^^                                     ^^  ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2309 -         impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
    2309 +         impl fmt::Write for LookForDecimalPoint<'_, '_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/ser/fmt.rs:38:6
       |
    38 | impl<'a> Serializer for &mut fmt::Formatter<'a> {
       |      ^^                                     ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    38 - impl<'a> Serializer for &mut fmt::Formatter<'a> {
    38 + impl Serializer for &mut fmt::Formatter<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/ser/impls.rs:62:6
       |
    62 | impl<'a> Serialize for fmt::Arguments<'a> {
       |      ^^                               ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    62 - impl<'a> Serialize for fmt::Arguments<'a> {
    62 + impl Serialize for fmt::Arguments<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde/src/format.rs:20:6
       |
    20 | impl<'a> Write for Buf<'a> {
       |      ^^                ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    20 - impl<'a> Write for Buf<'a> {
    20 + impl Write for Buf<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:254:10
        |
    254 |     impl<'de> Content<'de> {
        |          ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    254 -     impl<'de> Content<'de> {
    254 +     impl Content<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:333:10
        |
    333 |     impl<'de> ContentVisitor<'de> {
        |          ^^^                 ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    333 -     impl<'de> ContentVisitor<'de> {
    333 +     impl ContentVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:553:10
        |
    553 |     impl<'de> TagOrContentVisitor<'de> {
        |          ^^^                      ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    553 -     impl<'de> TagOrContentVisitor<'de> {
    553 +     impl TagOrContentVisitor<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'de
       --> serde/src/private/de.rs:937:10
        |
    937 |     impl<'de> Visitor<'de> for TagOrContentFieldVisitor {
        |          ^^^          ^^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    937 -     impl<'de> Visitor<'de> for TagOrContentFieldVisitor {
    937 +     impl Visitor<'_> for TagOrContentFieldVisitor {
        |

    warning: the following explicit lifetimes could be elided: 'de
        --> serde/src/private/de.rs:1014:10
         |
    1014 |     impl<'de> Visitor<'de> for TagContentOtherFieldVisitor {
         |          ^^^          ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1014 -     impl<'de> Visitor<'de> for TagContentOtherFieldVisitor {
    1014 +     impl Visitor<'_> for TagContentOtherFieldVisitor {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:1652:10
         |
    1652 |     impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
         |          ^^                                 ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1652 -     impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
    1652 +     impl<'de, E> ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:1735:15
         |
    1735 |     impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
         |               ^^                                                  ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1735 -     impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
    1735 +     impl<'de, E> Deserializer<'de> for ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2162:15
         |
    2162 |     impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
         |               ^^                                                       ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2162 -     impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
    2162 +     impl<'de, E> de::VariantAccess<'de> for VariantRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2259:15
         |
    2259 |     impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
         |               ^^                                                             ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2259 -     impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
    2259 +     impl<'de, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2288:15
         |
    2288 |     impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> {
         |               ^^                                               ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2288 -     impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> {
    2288 +     impl<'de> Visitor<'de> for InternallyTaggedUnitVisitor<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a, 'de
        --> serde/src/private/de.rs:2333:10
         |
    2333 |     impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> {
         |          ^^^  ^^          ^^^                          ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2333 -     impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> {
    2333 +     impl Visitor<'_> for UntaggedUnitVisitor<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2396:11
         |
    2396 | impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
         |           ^^                                           ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2396 - impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
    2396 + impl<'de, E> Deserializer<'de> for StrDeserializer<'_, E>
         |

    warning: the following explicit lifetimes could be elided: 'a, 'de
        --> serde/src/private/de.rs:2498:6
         |
    2498 | impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
         |      ^^  ^^^                         ^^  ^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2498 - impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
    2498 + impl<E> FlatMapDeserializer<'_, '_, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2522:6
         |
    2522 | impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
         |      ^^                                                    ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2522 - impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
    2522 + impl<'de, E> Deserializer<'de> for FlatMapDeserializer<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2658:6
         |
    2658 | impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
         |      ^^                                           ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2658 - impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
    2658 + impl<'de, E> MapAccess<'de> for FlatMapAccess<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/private/de.rs:2702:6
         |
    2702 | impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
         |      ^^                                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    2702 - impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
    2702 + impl<'de, E> MapAccess<'de> for FlatStructAccess<'_, 'de, E>
         |

    warning: the following explicit lifetimes could be elided: 'a
     --> serde/src/de/seed.rs:8:6
      |
    8 | impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
      |      ^^                                               ^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
      |
    8 - impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
    8 + impl<'de, T> DeserializeSeed<'de> for InPlaceSeed<'_, T>
      |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde_derive/src/internals/case.rs:124:6
        |
    124 | impl<'a> Display for ParseError<'a> {
        |      ^^                         ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
        = note: `-W clippy::needless-lifetimes` implied by `-W clippy::all`
        = help: to override `-W clippy::all` add `#[allow(clippy::needless_lifetimes)]`
    help: elide the lifetimes
        |
    124 - impl<'a> Display for ParseError<'a> {
    124 + impl Display for ParseError<'_> {
        |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde_derive/src/de.rs:3042:6
         |
    3042 | impl<'a> ToTokens for DeImplGenerics<'a> {
         |      ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    3042 - impl<'a> ToTokens for DeImplGenerics<'a> {
    3042 + impl ToTokens for DeImplGenerics<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde_derive/src/de.rs:3124:6
         |
    3124 | impl<'a> ToTokens for DeTypeGenerics<'a> {
         |      ^^                              ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    3124 - impl<'a> ToTokens for DeTypeGenerics<'a> {
    3124 + impl ToTokens for DeTypeGenerics<'_> {
         |

    warning: the following explicit lifetimes could be elided: 'a
      --> test_suite/tests/test_serde_path.rs:15:10
       |
    15 |     impl<'a> AssertNotSerdeDeserialize<'a> for Foo {}
       |          ^^                            ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
       = note: `-W clippy::needless-lifetimes` implied by `-W clippy::all`
       = help: to override `-W clippy::all` add `#[allow(clippy::needless_lifetimes)]`
    help: elide the lifetimes
       |
    15 -     impl<'a> AssertNotSerdeDeserialize<'a> for Foo {}
    15 +     impl AssertNotSerdeDeserialize<'_> for Foo {}
       |
2024-10-07 21:02:22 +02:00
David Tolnay 8e1ae68569 Resolve some needless_lifetimes clippy lints
warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/mod.rs:489:6
        |
    489 | impl<'a> Expected for &'a str {
        |      ^^                ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    489 - impl<'a> Expected for &'a str {
    489 + impl Expected for &str {
        |

    warning: the following explicit lifetimes could be elided: 'a
       --> serde/src/de/mod.rs:495:6
        |
    495 | impl<'a> Display for Expected + 'a {
        |      ^^                         ^^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
        |
    495 - impl<'a> Display for Expected + 'a {
    495 + impl Display for Expected + '_ {
        |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/mod.rs:1744:11
         |
    1744 | impl<'de, 'a, A> SeqAccess<'de> for &'a mut A
         |           ^^                         ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1744 - impl<'de, 'a, A> SeqAccess<'de> for &'a mut A
    1744 + impl<'de, A> SeqAccess<'de> for &mut A
         |

    warning: the following explicit lifetimes could be elided: 'a
        --> serde/src/de/mod.rs:1897:11
         |
    1897 | impl<'de, 'a, A> MapAccess<'de> for &'a mut A
         |           ^^                         ^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
         |
    1897 - impl<'de, 'a, A> MapAccess<'de> for &'a mut A
    1897 + impl<'de, A> MapAccess<'de> for &mut A
         |

    warning: the following explicit lifetimes could be elided: 'a, 'b
      --> serde/src/ser/fmt.rs:38:6
       |
    38 | impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
       |      ^^  ^^                  ^^                    ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    38 - impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
    38 + impl Serializer for &mut fmt::Formatter<'_> {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde_derive/src/internals/symbol.rs:49:6
       |
    49 | impl<'a> PartialEq<Symbol> for &'a Ident {
       |      ^^                         ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    49 - impl<'a> PartialEq<Symbol> for &'a Ident {
    49 + impl PartialEq<Symbol> for &Ident {
       |

    warning: the following explicit lifetimes could be elided: 'a
      --> serde_derive/src/internals/symbol.rs:61:6
       |
    61 | impl<'a> PartialEq<Symbol> for &'a Path {
       |      ^^                         ^^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
    help: elide the lifetimes
       |
    61 - impl<'a> PartialEq<Symbol> for &'a Path {
    61 + impl PartialEq<Symbol> for &Path {
       |
2024-10-07 20:58:23 +02:00
David Tolnay 31000e1874 Add a funding file 2024-09-23 15:38:18 -07:00
David Tolnay 4487cb26c7 Merge pull request #2822 from dtolnay/mapcontentdeserializer
Remove explicit ContentDeserializer construction in visit functions
2024-09-07 16:41:38 -07:00
David Tolnay aba4e18553 Remove explicit ContentDeserializer construction in visit functions 2024-09-07 16:31:03 -07:00
David Tolnay c82f2580b4 Merge pull request #2821 from dtolnay/clos
Eliminate closures capturing needlessly many type parameters
2024-09-06 16:54:36 -07:00
David Tolnay 1d7b009aec Eliminate closures capturing needlessly many type parameters 2024-09-06 16:29:41 -07:00
David Tolnay 89c4b02bf3 Release 1.0.210 2024-09-06 11:17:20 -07:00
David Tolnay eeb8e44cda Merge pull request #2818 from dtolnay/coreerror
Stabilize no-std Error trait
2024-09-06 11:16:43 -07:00
David Tolnay 785c2d9605 Stabilize no-std StdError trait 2024-09-06 11:12:13 -07:00
David Tolnay d549f048e1 Reformat parse_ip_impl definition and calls 2024-09-06 11:05:54 -07:00
David Tolnay 4c0dd63011 Delete attr support from core::net deserialization macros 2024-09-06 11:05:54 -07:00
David Tolnay 26fb134165 Relocate cfg attrs out of parse_ip_impl and parse_socket_impl 2024-09-06 11:05:53 -07:00
David Tolnay 07e614b52b Merge pull request #2817 from dtolnay/corenet
Delete doc(cfg) attribute from impls that are supported in no-std
2024-09-06 11:05:48 -07:00
David Tolnay b1f899fbe8 Delete doc(cfg) attribute from impls that are supported in no-std 2024-09-06 11:00:55 -07:00
David Tolnay b4f860e627 Merge pull request #2816 from MathiasKoch/chore/core-net
Implement serialize/deserialize for core::net instead of std::net
2024-09-06 10:59:24 -07:00
Mathias d940fe1b49 Reuse existing Buf wrapper as replacement for std::io::Write 2024-09-05 14:24:44 +02:00
Mathias f2899a9e06 Implement serialize/deserialize for core::net instead of std::net if running rust version newer than 1.77, where core::net was stabilized 2024-09-05 11:07:09 +02:00
David Tolnay 3aca38d2d3 Upload CI Cargo.lock for reproducing failures 2024-08-25 12:12:25 -07:00
Mingun 8b769fcc20 Remove unused component from tuple 2024-08-12 19:05:57 +05:00
Mingun 9c954264f4 Include variant aliases in error messages 2024-08-12 19:05:04 +05:00
Mingun 74b538b8ec Produce error about mismatched types of #[serde(with = "...")] and #[serde(default = "...")] attributes on the attribute itself 2024-08-05 00:29:37 +05:00
Mingun 291ec50d98 Add tests that ensures that error reported for a path for with and default attributes 2024-08-05 00:29:37 +05:00
Mingun 21c7fd1bd5 Add tests of #[serde(default)] attribute for units and unions 2024-07-23 21:00:11 +05:00
132 changed files with 6912 additions and 3430 deletions
+1
View File
@@ -0,0 +1 @@
github: dtolnay
+33 -28
View File
@@ -18,16 +18,22 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- run: cd test_suite && cargo test --features unstable
- uses: actions/upload-artifact@v6
if: always()
with:
name: Cargo.lock
path: Cargo.lock
continue-on-error: true
windows:
name: Test suite (windows)
runs-on: windows-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
@@ -40,15 +46,16 @@ jobs:
rust: [stable, beta]
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
- run: cd serde && cargo build --features rc
- run: cd serde && cargo build --no-default-features
- run: cd test_suite/no_std && cargo build
nightly:
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
name: Rust nightly${{matrix.os == 'windows' && ' (windows)' || ''}}
runs-on: ${{matrix.os}}-latest
strategy:
fail-fast: false
@@ -56,14 +63,14 @@ jobs:
os: [ubuntu, windows]
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- run: cd serde && cargo build
- run: cd serde && cargo build --no-default-features
- run: cd serde && cargo build --no-default-features --features alloc
- run: cd serde && cargo build --no-default-features --features rc,alloc
- run: cd serde && cargo build --no-default-features --features unstable
- run: cd serde && cargo test --features derive,rc,unstable
- run: cd serde_core && cargo test --features rc,unstable
- run: cd test_suite/no_std && cargo build
if: matrix.os != 'windows'
- run: cd serde_derive && cargo check --tests
@@ -77,46 +84,40 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: [1.31.0, 1.34.0]
rust: [1.56.0, 1.60.0]
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- 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 --no-default-features --features alloc
- run: cd serde && cargo build
derive:
name: Rust 1.56.0
name: Rust 1.68.0
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.56.0
- run: sed -i '/"test_suite"/d' Cargo.toml
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@1.68.0
- run: |
sed -i 's/proc-macro2 = { workspace = true/proc-macro2 = { version = "1"/' serde_derive*/Cargo.toml
sed -i 's/quote = { workspace = true/quote = { version = "1"/' serde_derive*/Cargo.toml
sed -i 's/syn = { workspace = true/syn = { version = "2"/' serde_derive*/Cargo.toml
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
alloc:
name: Rust 1.36.0
runs-on: ubuntu-latest
timeout-minutes: 45
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:
name: Minimal versions
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- run: cargo generate-lockfile -Z minimal-versions
- run: cargo check --locked --workspace
@@ -128,10 +129,11 @@ jobs:
env:
RUSTDOCFLAGS: -Dwarnings
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/install@cargo-docs-rs
- run: cargo docs-rs -p serde
- run: cargo docs-rs -p serde_core
- run: cargo docs-rs -p serde_derive
- run: cargo docs-rs -p serde_derive_internals
@@ -141,9 +143,10 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@clippy
- run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_core && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_derive && cargo clippy -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
@@ -154,10 +157,12 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@miri
with:
toolchain: nightly-2025-05-16 # https://github.com/rust-lang/miri/issues/4323
- run: cargo miri setup
- run: cd serde && cargo miri test --features derive,rc,unstable
- run: cd serde_core && cargo miri test --features rc,unstable
env:
MIRIFLAGS: -Zmiri-strict-provenance
- run: cd test_suite && cargo miri test --features unstable
@@ -170,7 +175,7 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/install@cargo-outdated
- run: cargo outdated --workspace --exit-code 1
+2 -4
View File
@@ -1,4 +1,2 @@
target/
**/*.rs.bk
*.sw[po]
Cargo.lock
/target/
/Cargo.lock
+3 -3
View File
@@ -27,11 +27,11 @@ pull request with your changes. If anything does not pass, typically it will be
easier to iterate and fix it locally than waiting for the CI servers to run
tests for you.
##### In the [`serde`] directory
##### In the [`serde_core`] directory
```sh
# Test all the example code in Serde documentation
cargo test --features derive
cargo test
```
##### In the [`test_suite`] directory
@@ -43,7 +43,7 @@ cargo +nightly test --features unstable
Note that this test suite currently only supports running on a nightly compiler.
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
[`serde_core`]: https://github.com/serde-rs/serde/tree/master/serde_core
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
## Conduct
+5 -1
View File
@@ -1,15 +1,19 @@
[workspace]
members = [
"serde",
"serde_core",
"serde_derive",
"serde_derive_internals",
"test_suite",
]
resolver = "2"
[patch.crates-io]
serde = { path = "serde" }
serde_core = { path = "serde_core" }
serde_derive = { path = "serde_derive" }
[workspace.dependencies]
proc-macro2 = { version = "1.0.74", default-features = false }
quote = { version = "1.0.35", default-features = false }
syn = { version = "2.0.46", default-features = false }
syn = { version = "2.0.81", default-features = false }
+5 -5
View File
@@ -1,4 +1,4 @@
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.31] [![serde_derive msrv]][Rust 1.56]
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.68]
[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master
[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster
@@ -6,8 +6,8 @@
[crates.io]: https://crates.io/crates/serde
[serde msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray
[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0/
[Rust 1.68]: https://blog.rust-lang.org/2023/03/09/Rust-1.68.0/
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
@@ -15,7 +15,7 @@
You may be looking for:
- [An overview of Serde](https://serde.rs/)
- [An overview of Serde](https://serde.rs)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
- [Examples](https://serde.rs/examples.html)
@@ -27,7 +27,7 @@ You may be looking for:
<details>
<summary>
Click to show Cargo.toml.
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
<a href="https://play.rust-lang.org/?edition=2021&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
</summary>
```toml
+1 -1
View File
@@ -6,7 +6,7 @@
You may be looking for:
- [An overview of Serde](https://serde.rs/)
- [An overview of Serde](https://serde.rs)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
- [Examples](https://serde.rs/examples.html)
+15 -22
View File
@@ -1,43 +1,36 @@
[package]
name = "serde"
version = "1.0.209"
version = "1.0.228"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "A generic serialization/deserialization framework"
documentation = "https://docs.rs/serde"
edition = "2018"
edition = "2021"
homepage = "https://serde.rs"
keywords = ["serde", "serialization", "no_std"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.31"
rust-version = "1.56"
[dependencies]
serde_core = { version = "=1.0.228", path = "../serde_core", default-features = false, features = ["result"] }
serde_derive = { version = "1", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1", path = "../serde_derive" }
[lib]
doc-scrape-examples = false
[package.metadata.playground]
features = ["derive", "rc"]
[package.metadata.docs.rs]
features = ["derive", "rc", "unstable"]
targets = ["x86_64-unknown-linux-gnu"]
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
# separately with serde's "derive" feature disabled. Every serde_derive release
# 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.209", path = "../serde_derive" }
rustdoc-args = [
"--generate-link-to-definition",
"--generate-macro-expansion",
"--extern-html-root-url=core=https://doc.rust-lang.org",
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
"--extern-html-root-url=std=https://doc.rust-lang.org",
]
### FEATURES #################################################################
@@ -50,20 +43,20 @@ derive = ["serde_derive"]
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
# Requires a dependency on the Rust standard library.
std = []
std = ["serde_core/std"]
# Provide impls for types that require unstable functionality. For tracking and
# discussion of unstable functionality please refer to this issue:
#
# https://github.com/serde-rs/serde/issues/812
unstable = []
unstable = ["serde_core/unstable"]
# Provide impls for types in the Rust core allocation and collections library
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
# be enabled without depending on all of std.
alloc = []
alloc = ["serde_core/alloc"]
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
# does not preserve identity and may result in multiple copies of the same data.
# Be sure that this is what you want before enabling this feature.
rc = []
rc = ["serde_core/rc"]
+29 -83
View File
@@ -1,6 +1,17 @@
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use std::str::{self, FromStr};
use std::str;
const PRIVATE: &str = "\
#[doc(hidden)]
pub mod __private$$ {
#[doc(hidden)]
pub use crate::private::*;
}
use serde_core::__private$$ as serde_core_private;
";
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
@@ -8,84 +19,37 @@ use std::str::{self, FromStr};
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-cfg=if_docsrs_then_no_serde_core");
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap();
let module = PRIVATE.replace("$$", &patch_version);
fs::write(out_dir.join("private.rs"), module).unwrap();
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
if minor >= 77 {
println!("cargo:rustc-check-cfg=cfg(feature, values(\"result\"))");
println!("cargo:rustc-check-cfg=cfg(if_docsrs_then_no_serde_core)");
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
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";
// TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
// stabilized in Rust 1.34:
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
if minor < 34 {
println!("cargo:rustc-cfg=no_core_try_from");
println!("cargo:rustc-cfg=no_num_nonzero_signed");
println!("cargo:rustc-cfg=no_systemtime_checked_add");
println!("cargo:rustc-cfg=no_relaxed_trait_bounds");
}
// f32::copysign and f64::copysign stabilized in Rust 1.35.
// https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html#copy-the-sign-of-a-floating-point-number-onto-another
if minor < 35 {
println!("cargo:rustc-cfg=no_float_copysign");
}
// Current minimum supported version of serde_derive crate is Rust 1.56.
if minor < 56 {
// Current minimum supported version of serde_derive crate is Rust 1.68.
if minor < 68 {
println!("cargo:rustc-cfg=no_serde_derive");
}
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
if minor < 60 {
println!("cargo:rustc-cfg=no_target_has_atomic");
// Allowlist of archs that support std::sync::atomic module. This is
// based on rustc's compiler/rustc_target/src/spec/*.rs.
let has_atomic64 = target.starts_with("x86_64")
|| target.starts_with("i686")
|| target.starts_with("aarch64")
|| target.starts_with("powerpc64")
|| target.starts_with("sparc64")
|| target.starts_with("mips64el")
|| target.starts_with("riscv64");
let has_atomic32 = has_atomic64 || emscripten;
if minor < 34 || !has_atomic64 {
println!("cargo:rustc-cfg=no_std_atomic64");
}
if minor < 34 || !has_atomic32 {
println!("cargo:rustc-cfg=no_std_atomic");
}
}
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
if minor < 64 {
println!("cargo:rustc-cfg=no_core_cstr");
}
// Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74
// https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis
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 {
@@ -94,30 +58,12 @@ fn main() {
}
fn rustc_minor_version() -> Option<u32> {
let rustc = match env::var_os("RUSTC") {
Some(rustc) => rustc,
None => return None,
};
let output = match Command::new(rustc).arg("--version").output() {
Ok(output) => output,
Err(_) => return None,
};
let version = match str::from_utf8(&output.stdout) {
Ok(version) => version,
Err(_) => return None,
};
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
let next = match pieces.next() {
Some(next) => next,
None => return None,
};
u32::from_str(next).ok()
pieces.next()?.parse().ok()
}
+1
View File
@@ -0,0 +1 @@
../../serde_core/src
+7 -2
View File
@@ -1,6 +1,11 @@
// No longer used. Old versions of serde used this macro for supporting targets
// that did not yet have 128-bit integer support.
#[macro_export]
#[deprecated = "
This macro has no effect on any version of Serde released in the past 2 years.
It was used long ago in crates that needed to support Rustc older than 1.26.0,
or Emscripten targets older than 1.40.0, which did not yet have 128-bit integer
support. These days Serde requires a Rust compiler newer than that so 128-bit
integers are always supported.
"]
#[doc(hidden)]
macro_rules! serde_if_integer128 {
($($tt:tt)*) => {
+107 -162
View File
@@ -9,7 +9,7 @@
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website <https://serde.rs/> for additional documentation and
//! See the Serde website <https://serde.rs> for additional documentation and
//! usage examples.
//!
//! ## Design
@@ -95,7 +95,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.209")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.228")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Show which crate feature enables conditionally compiled APIs in documentation.
@@ -106,7 +106,12 @@
//
// https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![allow(
unknown_lints,
bare_trait_objects,
deprecated,
mismatched_lifetime_syntaxes
)]
// Ignored clippy and clippy_pedantic lints
#![allow(
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
@@ -114,7 +119,7 @@
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
clippy::semicolon_if_nothing_returned,
// not available in our oldest supported compiler
clippy::empty_enum,
clippy::empty_enums,
clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
// integer and float ser/de requires these sorts of casts
clippy::cast_possible_truncation,
@@ -144,6 +149,8 @@
clippy::too_many_lines,
// preference
clippy::doc_markdown,
clippy::elidable_lifetime_names,
clippy::needless_lifetimes,
clippy::unseparated_literal_suffix,
// false positive
clippy::needless_doctest_main,
@@ -161,166 +168,103 @@
#[cfg(feature = "alloc")]
extern crate alloc;
/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
mod core {
#[cfg(not(feature = "std"))]
pub use core::*;
#[cfg(feature = "std")]
pub use std::*;
}
pub use self::core::{f32, f64};
pub use self::core::{i16, i32, i64, i8, isize};
pub use self::core::{iter, num, ptr, str};
pub use self::core::{u16, u32, u64, u8, usize};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::core::{cmp, mem, slice};
pub use self::core::cell::{Cell, RefCell};
pub use self::core::clone;
pub use self::core::cmp::Reverse;
pub use self::core::convert;
pub use self::core::default;
pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite};
pub use self::core::marker::{self, PhantomData};
pub use self::core::num::Wrapping;
pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo};
pub use self::core::option;
pub use self::core::result;
pub use self::core::time::Duration;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "std")]
pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString};
#[cfg(feature = "std")]
pub use std::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec;
#[cfg(feature = "std")]
pub use std::vec::Vec;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::boxed::Box;
#[cfg(feature = "std")]
pub use std::boxed::Box;
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::sync::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::sync::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")]
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
pub use self::core::ffi::CStr;
#[cfg(feature = "std")]
pub use std::ffi::CStr;
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
pub use alloc::ffi::CString;
#[cfg(feature = "std")]
pub use std::ffi::CString;
#[cfg(feature = "std")]
pub use std::{error, net};
#[cfg(feature = "std")]
pub use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
pub use std::ffi::{OsStr, OsString};
#[cfg(feature = "std")]
pub use std::hash::{BuildHasher, Hash};
#[cfg(feature = "std")]
pub use std::io::Write;
#[cfg(feature = "std")]
pub use std::path::{Path, PathBuf};
#[cfg(feature = "std")]
pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "std")]
pub use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))]
pub use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize, Ordering,
};
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(all(feature = "std", not(no_target_has_atomic)))]
pub use std::sync::atomic::Ordering;
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))]
pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))]
pub use std::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))]
pub use std::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))]
pub use std::sync::atomic::{AtomicIsize, AtomicUsize};
#[cfg(not(no_core_num_saturating))]
pub use self::core::num::Saturating;
}
// None of this crate's error handling needs the `From::from` error conversion
// performed implicitly by the `?` operator or the standard library's `try!`
// macro. This simplified macro gives a 5.5% improvement in compile time
// compared to standard `try!`, and 9% improvement compared to `?`.
macro_rules! tri {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => return Err(err),
}
};
}
////////////////////////////////////////////////////////////////////////////////
// Rustdoc has a lot of shortcomings related to cross-crate re-exports that make
// the rendered documentation of serde_core traits in serde more challenging to
// understand than the equivalent documentation of the same items in serde_core.
// https://github.com/rust-lang/rust/labels/A-cross-crate-reexports
// So, just for the purpose of docs.rs documentation, we inline the contents of
// serde_core into serde. This sidesteps all the cross-crate rustdoc bugs.
#[cfg(docsrs)]
#[macro_use]
#[path = "core/crate_root.rs"]
mod crate_root;
#[cfg(docsrs)]
#[macro_use]
#[path = "core/macros.rs"]
mod macros;
#[macro_use]
#[cfg(not(docsrs))]
macro_rules! crate_root {
() => {
/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
mod core {
#[cfg(not(feature = "std"))]
pub use core::*;
#[cfg(feature = "std")]
pub use std::*;
}
pub use self::core::{f32, f64};
pub use self::core::{ptr, str};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::core::slice;
pub use self::core::clone;
pub use self::core::convert;
pub use self::core::default;
pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite};
pub use self::core::marker::{self, PhantomData};
pub use self::core::option;
pub use self::core::result;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "std")]
pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString};
#[cfg(feature = "std")]
pub use std::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec;
#[cfg(feature = "std")]
pub use std::vec::Vec;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::boxed::Box;
#[cfg(feature = "std")]
pub use std::boxed::Box;
}
// None of this crate's error handling needs the `From::from` error conversion
// performed implicitly by the `?` operator or the standard library's `try!`
// macro. This simplified macro gives a 5.5% improvement in compile time
// compared to standard `try!`, and 9% improvement compared to `?`.
#[cfg(not(no_serde_derive))]
macro_rules! tri {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => return Err(err),
}
};
}
////////////////////////////////////////////////////////////////////////////////
pub use serde_core::{
de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer,
};
// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
mod private;
include!(concat!(env!("OUT_DIR"), "/private.rs"));
};
}
crate_root!();
mod integer128;
pub mod de;
pub mod ser;
#[doc(inline)]
pub use crate::de::{Deserialize, Deserializer};
#[doc(inline)]
pub use crate::ser::{Serialize, Serializer};
// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
#[path = "private/mod.rs"]
pub mod __private;
#[path = "de/seed.rs"]
mod seed;
#[cfg(not(any(feature = "std", feature = "unstable")))]
mod std_error;
// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
@@ -334,7 +278,8 @@ extern crate serde_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")))]
mod actually_private {
pub struct T;
#[macro_export]
#[doc(hidden)]
macro_rules! __require_serde_not_serde_core {
() => {};
}
+856 -150
View File
File diff suppressed because it is too large Load Diff
+2 -32
View File
@@ -3,11 +3,8 @@ pub mod de;
#[cfg(not(no_serde_derive))]
pub mod ser;
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
pub mod doc;
pub use crate::lib::clone::Clone;
pub use crate::lib::convert::{From, Into};
pub use crate::lib::convert::{From, Into, TryFrom};
pub use crate::lib::default::Default;
pub use crate::lib::fmt::{self, Formatter};
pub use crate::lib::marker::PhantomData;
@@ -15,34 +12,7 @@ pub use crate::lib::option::Option::{self, None, Some};
pub use crate::lib::ptr;
pub use crate::lib::result::Result::{self, Err, Ok};
pub use self::string::from_utf8_lossy;
pub use crate::serde_core_private::string::from_utf8_lossy;
#[cfg(any(feature = "alloc", feature = "std"))]
pub use crate::lib::{ToString, Vec};
#[cfg(not(no_core_try_from))]
pub use crate::lib::convert::TryFrom;
mod string {
use crate::lib::*;
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
String::from_utf8_lossy(bytes)
}
// The generated code calls this like:
//
// let value = &_serde::__private::from_utf8_lossy(bytes);
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
//
// so it is okay for the return type to be different from the std case as long
// as the above works.
#[cfg(not(any(feature = "std", feature = "alloc")))]
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
// Three unicode replacement characters if it fails. They look like a
// white-on-black question mark. The user will recognize it as invalid
// UTF-8.
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
}
}
+24 -2
View File
@@ -54,9 +54,11 @@ enum Unsupported {
Sequence,
Tuple,
TupleStruct,
#[cfg(not(any(feature = "std", feature = "alloc")))]
Enum,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl Display for Unsupported {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
@@ -70,6 +72,7 @@ impl Display for Unsupported {
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
#[cfg(not(any(feature = "std", feature = "alloc")))]
Unsupported::Enum => formatter.write_str("an enum"),
}
}
@@ -87,6 +90,7 @@ where
}
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<S> Serializer for TaggedSerializer<S>
where
S: Serializer,
@@ -353,6 +357,7 @@ mod content {
}
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
where
M: ser::SerializeMap,
@@ -393,6 +398,7 @@ mod content {
}
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
where
M: ser::SerializeMap,
@@ -460,6 +466,7 @@ mod content {
),
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl Serialize for Content {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -552,6 +559,7 @@ mod content {
}
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> Serializer for ContentSerializer<E>
where
E: ser::Error,
@@ -763,6 +771,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeSeq for SerializeSeq<E>
where
E: ser::Error,
@@ -789,6 +798,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeTuple for SerializeTuple<E>
where
E: ser::Error,
@@ -816,6 +826,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
where
E: ser::Error,
@@ -845,6 +856,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
where
E: ser::Error,
@@ -877,6 +889,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeMap for SerializeMap<E>
where
E: ser::Error,
@@ -928,6 +941,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeStruct for SerializeStruct<E>
where
E: ser::Error,
@@ -957,6 +971,7 @@ mod content {
error: PhantomData<E>,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
where
E: ser::Error,
@@ -1001,6 +1016,7 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
where
M: SerializeMap + 'a,
@@ -1095,9 +1111,9 @@ where
self,
_: &'static str,
_: u32,
_: &'static str,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Err(Self::bad_type(Unsupported::Enum))
self.0.serialize_entry(variant, &())
}
fn serialize_newtype_struct<T>(
@@ -1182,6 +1198,7 @@ where
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
where
M: SerializeMap + 'a,
@@ -1220,6 +1237,7 @@ where
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
where
M: SerializeMap + 'a,
@@ -1261,6 +1279,7 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, M> ser::SerializeTupleVariant for FlatMapSerializeTupleVariantAsMapValue<'a, M>
where
M: SerializeMap + 'a,
@@ -1307,6 +1326,7 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
where
M: SerializeMap + 'a,
@@ -1337,6 +1357,7 @@ pub struct AdjacentlyTaggedEnumVariant {
pub variant_name: &'static str,
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl Serialize for AdjacentlyTaggedEnumVariant {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -1350,6 +1371,7 @@ impl Serialize for AdjacentlyTaggedEnumVariant {
// that is not recognized.
pub struct CannotSerializeVariant<T>(pub T);
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<T> Display for CannotSerializeVariant<T>
where
T: Debug,
+70
View File
@@ -0,0 +1,70 @@
[package]
name = "serde_core"
version = "1.0.228"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "Serde traits only, with no support for derive -- use the `serde` crate instead"
documentation = "https://docs.rs/serde_core"
edition = "2021"
homepage = "https://serde.rs"
keywords = ["serde", "serialization", "no_std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.56"
[dev-dependencies]
serde = { version = "1", path = "../serde" }
serde_derive = { version = "1", path = "../serde_derive" }
[package.metadata.playground]
features = ["rc", "result"]
[package.metadata.docs.rs]
features = ["rc", "result", "unstable"]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = [
"--generate-link-to-definition",
"--generate-macro-expansion",
"--extern-html-root-url=core=https://doc.rust-lang.org",
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
"--extern-html-root-url=std=https://doc.rust-lang.org",
]
# 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
# separately with serde's "derive" feature disabled. Every serde_derive release
# 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.228", path = "../serde_derive" }
### FEATURES #################################################################
[features]
default = ["std", "result"]
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
# Requires a dependency on the Rust standard library.
std = []
# Provide impls for types that require unstable functionality. For tracking and
# discussion of unstable functionality please refer to this issue:
#
# https://github.com/serde-rs/serde/issues/812
unstable = []
# Provide impls for types in the Rust core allocation and collections library
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
# be enabled without depending on all of std.
alloc = []
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
# does not preserve identity and may result in multiple copies of the same data.
# Be sure that this is what you want before enabling this feature.
rc = []
# Provide impls for Result<T, E>. Convenient in some contexts but can lead to
# confusion if ? or unwrap are used incautiously.
result = []
+1
View File
@@ -0,0 +1 @@
../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../LICENSE-MIT
+28
View File
@@ -0,0 +1,28 @@
The `serde_core` crate contains Serde's trait definitions with **no support for
#\[derive()\]**.
In crates that derive an implementation of `Serialize` or `Deserialize`, you
must depend on the [`serde`] crate, not `serde_core`.
[`serde`]: https://crates.io/crates/serde
In crates that handwrite implementations of Serde traits, or only use them as
trait bounds, depending on `serde_core` is permitted. But `serde` re-exports all
of these traits and can be used for this use case too. If in doubt, disregard
`serde_core` and always use `serde`.
Crates that depend on `serde_core` instead of `serde` are able to compile in
parallel with `serde_derive` even when `serde`'s "derive" feature is turned on,
as shown in the following build timings.
<br>
| When `serde_json` depends on `serde` |
|---|
| <img src="https://github.com/user-attachments/assets/78dc179c-6ab1-4059-928c-1474b0d9d0bb"> |
<br>
| When `serde_json` depends on `serde_core` |
|---|
| <img src="https://github.com/user-attachments/assets/6b6cff5e-3e45-4ac7-9db1-d99ee8b9f5f7"> |
+113
View File
@@ -0,0 +1,113 @@
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use std::str;
const PRIVATE: &str = "\
#[doc(hidden)]
pub mod __private$$ {
#[doc(hidden)]
pub use crate::private::*;
}
";
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap();
let module = PRIVATE.replace("$$", &patch_version);
fs::write(out_dir.join("private.rs"), module).unwrap();
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
if minor >= 77 {
println!("cargo:rustc-check-cfg=cfg(if_docsrs_then_no_serde_core)");
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
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_target_has_atomic)");
}
let target = env::var("TARGET").unwrap();
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
if minor < 60 {
println!("cargo:rustc-cfg=no_target_has_atomic");
// Allowlist of archs that support std::sync::atomic module. This is
// based on rustc's compiler/rustc_target/src/spec/*.rs.
let has_atomic64 = target.starts_with("x86_64")
|| target.starts_with("i686")
|| target.starts_with("aarch64")
|| target.starts_with("powerpc64")
|| target.starts_with("sparc64")
|| target.starts_with("mips64el")
|| target.starts_with("riscv64");
let has_atomic32 = has_atomic64 || emscripten;
if minor < 34 || !has_atomic64 {
println!("cargo:rustc-cfg=no_std_atomic64");
}
if minor < 34 || !has_atomic32 {
println!("cargo:rustc-cfg=no_std_atomic");
}
}
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
if minor < 64 {
println!("cargo:rustc-cfg=no_core_cstr");
}
// Current minimum supported version of serde_derive crate is Rust 1.68.
if minor < 68 {
println!("cargo:rustc-cfg=no_serde_derive");
}
// Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74
// https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis
if minor < 74 {
println!("cargo:rustc-cfg=no_core_num_saturating");
}
// Support for core::net stabilized in Rust 1.77.
// https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html
if minor < 77 {
println!("cargo:rustc-cfg=no_core_net");
}
// 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");
}
// The Error trait became available in core in 1.81.
// https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
if minor < 81 {
println!("cargo:rustc-cfg=no_core_error");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+171
View File
@@ -0,0 +1,171 @@
macro_rules! crate_root {
() => {
/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
mod core {
#[cfg(not(feature = "std"))]
pub use core::*;
#[cfg(feature = "std")]
pub use std::*;
}
pub use self::core::{f32, f64};
pub use self::core::{iter, num, str};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::core::{cmp, mem};
pub use self::core::cell::{Cell, RefCell};
pub use self::core::cmp::Reverse;
pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite};
pub use self::core::marker::PhantomData;
pub use self::core::num::Wrapping;
pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo};
pub use self::core::result;
pub use self::core::time::Duration;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "std")]
pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString};
#[cfg(feature = "std")]
pub use std::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec;
#[cfg(feature = "std")]
pub use std::vec::Vec;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::boxed::Box;
#[cfg(feature = "std")]
pub use std::boxed::Box;
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::rc::{Rc, Weak as RcWeak};
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::sync::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::sync::{Arc, Weak as ArcWeak};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")]
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
pub use self::core::ffi::CStr;
#[cfg(feature = "std")]
pub use std::ffi::CStr;
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
pub use alloc::ffi::CString;
#[cfg(feature = "std")]
pub use std::ffi::CString;
#[cfg(all(not(no_core_net), not(feature = "std")))]
pub use self::core::net;
#[cfg(feature = "std")]
pub use std::net;
#[cfg(feature = "std")]
pub use std::error;
#[cfg(feature = "std")]
pub use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
pub use std::ffi::{OsStr, OsString};
#[cfg(feature = "std")]
pub use std::hash::{BuildHasher, Hash};
#[cfg(feature = "std")]
pub use std::io::Write;
#[cfg(feature = "std")]
pub use std::path::{Path, PathBuf};
#[cfg(feature = "std")]
pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "std")]
pub use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))]
pub use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
AtomicU8, AtomicUsize, Ordering,
};
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(all(feature = "std", not(no_target_has_atomic)))]
pub use std::sync::atomic::Ordering;
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))]
pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))]
pub use std::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))]
pub use std::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))]
pub use std::sync::atomic::{AtomicIsize, AtomicUsize};
#[cfg(not(no_core_num_saturating))]
pub use self::core::num::Saturating;
}
// None of this crate's error handling needs the `From::from` error conversion
// performed implicitly by the `?` operator or the standard library's `try!`
// macro. This simplified macro gives a 5.5% improvement in compile time
// compared to standard `try!`, and 9% improvement compared to `?`.
macro_rules! tri {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => return Err(err),
}
};
}
#[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/de/mod.rs")]
pub mod de;
#[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/ser/mod.rs")]
pub mod ser;
#[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/format.rs")]
mod format;
#[doc(inline)]
pub use crate::de::{Deserialize, Deserializer};
#[doc(inline)]
pub use crate::ser::{Serialize, Serializer};
// Used by generated code. Not public API.
#[doc(hidden)]
#[cfg_attr(
all(docsrs, if_docsrs_then_no_serde_core),
path = "core/private/mod.rs"
)]
mod private;
// Used by declarative macro generated code. Not public API.
#[doc(hidden)]
pub mod __private {
#[doc(hidden)]
pub use crate::private::doc;
#[doc(hidden)]
pub use core::result::Result;
}
include!(concat!(env!("OUT_DIR"), "/private.rs"));
#[cfg(all(not(feature = "std"), no_core_error))]
#[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/std_error.rs")]
mod std_error;
};
}
@@ -4,11 +4,10 @@ use crate::de::{
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, Unexpected, VariantAccess,
Visitor,
};
use crate::seed::InPlaceSeed;
use crate::private::{self, InPlaceSeed};
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::de::size_hint;
use crate::private::size_hint;
////////////////////////////////////////////////////////////////////////////////
@@ -80,10 +79,9 @@ impl<'de> Deserialize<'de> for bool {
////////////////////////////////////////////////////////////////////////////////
macro_rules! impl_deserialize_num {
($primitive:ident, $nonzero:ident $(cfg($($cfg:tt)*))*, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => {
($primitive:ident, $nonzero:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => {
impl_deserialize_num!($primitive, $deserialize $($method!($($val : $visit)*);)*);
$(#[cfg($($cfg)*)])*
impl<'de> Deserialize<'de> for num::$nonzero {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -228,12 +226,12 @@ macro_rules! num_as_copysign_self {
where
E: Error,
{
#[cfg(any(no_float_copysign, not(feature = "std")))]
#[cfg(not(feature = "std"))]
{
Ok(v as Self::Value)
}
#[cfg(all(not(no_float_copysign), feature = "std"))]
#[cfg(feature = "std")]
{
// Preserve sign of NaN. The `as` produces a nondeterministic sign.
let sign = if v.is_sign_positive() { 1.0 } else { -1.0 };
@@ -250,13 +248,8 @@ macro_rules! int_to_int {
where
E: Error,
{
if Self::Value::min_value() as i64 <= v as i64
&& v as i64 <= Self::Value::max_value() as i64
{
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
Self::Value::try_from(v as i64)
.map_err(|_| Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
};
@@ -265,10 +258,8 @@ macro_rules! int_to_int {
where
E: Error,
{
if $primitive::min_value() as i64 <= v as i64
&& v as i64 <= $primitive::max_value() as i64
{
if let Some(nonzero) = Self::Value::new(v as $primitive) {
if let Ok(v) = $primitive::try_from(v as i64) {
if let Some(nonzero) = Self::Value::new(v) {
return Ok(nonzero);
}
}
@@ -299,11 +290,13 @@ macro_rules! int_to_uint {
where
E: Error,
{
if 0 <= v && v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
if 0 <= v {
#[allow(irrefutable_let_patterns)]
if let Ok(v) = Self::Value::try_from(v as u64) {
return Ok(v as Self::Value);
}
}
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
};
@@ -312,9 +305,12 @@ macro_rules! int_to_uint {
where
E: Error,
{
if 0 < v && v as u64 <= $primitive::max_value() as u64 {
if let Some(nonzero) = Self::Value::new(v as $primitive) {
return Ok(nonzero);
if 0 < v {
#[allow(irrefutable_let_patterns)]
if let Ok(v) = $primitive::try_from(v as u64) {
if let Some(nonzero) = Self::Value::new(v) {
return Ok(nonzero);
}
}
}
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
@@ -344,11 +340,8 @@ macro_rules! uint_to_self {
where
E: Error,
{
if v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self))
}
Self::Value::try_from(v as u64)
.map_err(|_| Error::invalid_value(Unexpected::Unsigned(v as u64), &self))
}
};
@@ -357,8 +350,8 @@ macro_rules! uint_to_self {
where
E: Error,
{
if v as u64 <= $primitive::max_value() as u64 {
if let Some(nonzero) = Self::Value::new(v as $primitive) {
if let Ok(v) = $primitive::try_from(v as u64) {
if let Some(nonzero) = Self::Value::new(v) {
return Ok(nonzero);
}
}
@@ -371,7 +364,7 @@ macro_rules! uint_to_self {
where
E: Error,
{
if v as u64 <= $primitive::MAX as u64 {
if let Ok(v) = $primitive::try_from(v as u64) {
Ok(Saturating(v as $primitive))
} else {
Ok(Saturating($primitive::MAX))
@@ -381,14 +374,14 @@ macro_rules! uint_to_self {
}
impl_deserialize_num! {
i8, NonZeroI8 cfg(not(no_num_nonzero_signed)), deserialize_i8
i8, NonZeroI8, deserialize_i8
num_self!(i8:visit_i8);
int_to_int!(i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i16, NonZeroI16 cfg(not(no_num_nonzero_signed)), deserialize_i16
i16, NonZeroI16, deserialize_i16
num_self!(i16:visit_i16);
num_as_self!(i8:visit_i8);
int_to_int!(i32:visit_i32 i64:visit_i64);
@@ -396,7 +389,7 @@ impl_deserialize_num! {
}
impl_deserialize_num! {
i32, NonZeroI32 cfg(not(no_num_nonzero_signed)), deserialize_i32
i32, NonZeroI32, deserialize_i32
num_self!(i32:visit_i32);
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i64:visit_i64);
@@ -404,14 +397,14 @@ impl_deserialize_num! {
}
impl_deserialize_num! {
i64, NonZeroI64 cfg(not(no_num_nonzero_signed)), deserialize_i64
i64, NonZeroI64, deserialize_i64
num_self!(i64:visit_i64);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
isize, NonZeroIsize cfg(not(no_num_nonzero_signed)), deserialize_i64
isize, NonZeroIsize, deserialize_i64
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
@@ -476,9 +469,7 @@ macro_rules! num_128 {
where
E: Error,
{
if v as i128 >= Self::Value::min_value() as i128
&& v as u128 <= Self::Value::max_value() as u128
{
if v as i128 >= Self::Value::MIN as i128 && v as u128 <= Self::Value::MAX as u128 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(
@@ -494,9 +485,7 @@ macro_rules! num_128 {
where
E: Error,
{
if v as i128 >= $primitive::min_value() as i128
&& v as u128 <= $primitive::max_value() as u128
{
if v as i128 >= $primitive::MIN as i128 && v as u128 <= $primitive::MAX as u128 {
if let Some(nonzero) = Self::Value::new(v as $primitive) {
Ok(nonzero)
} else {
@@ -528,7 +517,7 @@ macro_rules! num_128 {
}
impl_deserialize_num! {
i128, NonZeroI128 cfg(not(no_num_nonzero_signed)), deserialize_i128
i128, NonZeroI128, deserialize_i128
num_self!(i128:visit_i128);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
@@ -1583,12 +1572,9 @@ map_impl! {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", not(no_core_net)))]
macro_rules! parse_ip_impl {
(
$(#[$attr:meta])*
$ty:ty, $expecting:expr, $size:tt
) => {
$(#[$attr])*
($ty:ty, $expecting:expr, $size:tt) => {
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1604,7 +1590,7 @@ macro_rules! parse_ip_impl {
};
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
macro_rules! variant_identifier {
(
$name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
@@ -1679,7 +1665,7 @@ macro_rules! variant_identifier {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
macro_rules! deserialize_enum {
(
$name:ident $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
@@ -1716,8 +1702,7 @@ macro_rules! deserialize_enum {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl<'de> Deserialize<'de> for net::IpAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1736,25 +1721,18 @@ impl<'de> Deserialize<'de> for net::IpAddr {
}
}
parse_ip_impl! {
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::Ipv4Addr, "IPv4 address", 4
}
#[cfg(any(feature = "std", not(no_core_net)))]
parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4);
parse_ip_impl! {
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::Ipv6Addr, "IPv6 address", 16
}
#[cfg(any(feature = "std", not(no_core_net)))]
parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16);
#[cfg(any(feature = "std", not(no_core_net)))]
macro_rules! parse_socket_impl {
(
$(#[$attr:meta])*
$ty:ty, $expecting:tt,
$new:expr,
) => {
$(#[$attr])*
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1770,8 +1748,7 @@ macro_rules! parse_socket_impl {
};
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl<'de> Deserialize<'de> for net::SocketAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1790,16 +1767,14 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
}
}
#[cfg(any(feature = "std", not(no_core_net)))]
parse_socket_impl! {
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::SocketAddrV4, "IPv4 socket address",
|(ip, port)| net::SocketAddrV4::new(ip, port),
}
#[cfg(any(feature = "std", not(no_core_net)))]
parse_socket_impl! {
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
net::SocketAddrV6, "IPv6 socket address",
|(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0),
}
@@ -2198,7 +2173,7 @@ impl<'de> Deserialize<'de> for Duration {
b"secs" => Ok(Field::Secs),
b"nanos" => Ok(Field::Nanos),
_ => {
let value = crate::__private::from_utf8_lossy(value);
let value = private::string::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
@@ -2429,13 +2404,9 @@ impl<'de> Deserialize<'de> for SystemTime {
const FIELDS: &[&str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = tri!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
#[cfg(not(no_systemtime_checked_add))]
let ret = UNIX_EPOCH
UNIX_EPOCH
.checked_add(duration)
.ok_or_else(|| D::Error::custom("overflow deserializing SystemTime"));
#[cfg(no_systemtime_checked_add)]
let ret = Ok(UNIX_EPOCH + duration);
ret
.ok_or_else(|| D::Error::custom("overflow deserializing SystemTime"))
}
}
@@ -2493,6 +2464,7 @@ mod range {
use crate::lib::*;
use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
use crate::private;
pub const FIELDS: &[&str] = &["start", "end"];
@@ -2538,7 +2510,7 @@ mod range {
b"start" => Ok(Field::Start),
b"end" => Ok(Field::End),
_ => {
let value = crate::__private::from_utf8_lossy(value);
let value = private::string::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
@@ -2651,6 +2623,7 @@ mod range_from {
use crate::lib::*;
use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
use crate::private;
pub const FIELDS: &[&str] = &["start"];
@@ -2693,7 +2666,7 @@ mod range_from {
match value {
b"start" => Ok(Field::Start),
_ => {
let value = crate::__private::from_utf8_lossy(value);
let value = private::string::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
@@ -2789,6 +2762,7 @@ mod range_to {
use crate::lib::*;
use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
use crate::private;
pub const FIELDS: &[&str] = &["end"];
@@ -2831,7 +2805,7 @@ mod range_to {
match value {
b"end" => Ok(Field::End),
_ => {
let value = crate::__private::from_utf8_lossy(value);
let value = private::string::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
@@ -3003,6 +2977,8 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "result")]
#[cfg_attr(docsrs, doc(cfg(feature = "result")))]
impl<'de, T, E> Deserialize<'de> for Result<T, E>
where
T: Deserialize<'de>,
@@ -3160,13 +3136,13 @@ atomic_impl! {
AtomicU64 "64"
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
struct FromStrVisitor<T> {
expecting: &'static str,
ty: PhantomData<T>,
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
impl<T> FromStrVisitor<T> {
fn new(expecting: &'static str) -> Self {
FromStrVisitor {
@@ -3176,7 +3152,7 @@ impl<T> FromStrVisitor<T> {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
impl<'de, T> Visitor<'de> for FromStrVisitor<T>
where
T: str::FromStr,
@@ -101,8 +101,8 @@
//! - SocketAddrV6
//!
//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html
//! [`Deserialize`]: ../trait.Deserialize.html
//! [`Deserializer`]: ../trait.Deserializer.html
//! [`Deserialize`]: crate::Deserialize
//! [`Deserializer`]: crate::Deserializer
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
//! [`postcard`]: https://github.com/jamesmunns/postcard
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
@@ -118,17 +118,14 @@ use crate::lib::*;
pub mod value;
mod format;
mod ignored_any;
mod impls;
pub(crate) mod size_hint;
pub use self::ignored_any::IgnoredAny;
#[cfg(not(any(feature = "std", feature = "unstable")))]
#[cfg(all(not(feature = "std"), no_core_error))]
#[doc(no_inline)]
pub use crate::std_error::Error as StdError;
#[cfg(all(feature = "unstable", not(feature = "std")))]
#[cfg(not(any(feature = "std", no_core_error)))]
#[doc(no_inline)]
pub use core::error::Error as StdError;
#[cfg(feature = "std")]
@@ -159,6 +156,12 @@ macro_rules! declare_error_trait {
/// type appropriate for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Error` is not satisfied",
)
)]
pub trait Error: Sized $(+ $($supertrait)::+)* {
/// Raised when there is general error when deserializing a type.
///
@@ -207,7 +210,7 @@ macro_rules! declare_error_trait {
/// containing an integer, the unexpected type is the integer and the
/// expected type is the string.
#[cold]
fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self {
fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
}
@@ -225,7 +228,7 @@ macro_rules! declare_error_trait {
/// that is not valid UTF-8, the unexpected value is the bytes and the
/// expected value is a string.
#[cold]
fn invalid_value(unexp: Unexpected, exp: &Expected) -> Self {
fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp))
}
@@ -239,7 +242,7 @@ macro_rules! declare_error_trait {
/// expected. For example `exp` might say that a tuple of size 6 was
/// expected.
#[cold]
fn invalid_length(len: usize, exp: &Expected) -> Self {
fn invalid_length(len: usize, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid length {}, expected {}", len, exp))
}
@@ -472,6 +475,12 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// ));
/// # }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Expected` is not satisfied",
)
)]
pub trait Expected {
/// Format an explanation of what data was being expected. Same signature as
/// the `Display` and `Debug` traits.
@@ -487,13 +496,13 @@ where
}
}
impl<'a> Expected for &'a str {
impl Expected for &str {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self)
}
}
impl<'a> Display for Expected + 'a {
impl Display for dyn Expected + '_ {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Expected::fmt(self, formatter)
}
@@ -535,6 +544,9 @@ impl<'a> Display for Expected + 'a {
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
// Prevents `serde_core::de::Deserialize` appearing in the error message
// in projects with no direct dependency on serde_core.
message = "the trait bound `{Self}: serde::Deserialize<'de>` is not satisfied",
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",
)
@@ -611,6 +623,12 @@ pub trait Deserialize<'de>: Sized {
/// lifetimes].
///
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeOwned` is not satisfied",
)
)]
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
@@ -776,6 +794,12 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// # Ok(())
/// # }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeSeed<'de>` is not satisfied",
)
)]
pub trait DeserializeSeed<'de>: Sized {
/// The type produced by using this seed.
type Value;
@@ -912,6 +936,12 @@ where
/// a basic JSON `Deserializer`.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Deserializer<'de>` is not satisfied",
)
)]
pub trait Deserializer<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1227,13 +1257,9 @@ pub trait Deserializer<'de>: Sized {
// Not public API.
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
#[doc(hidden)]
fn __deserialize_content<V>(
self,
_: crate::actually_private::T,
visitor: V,
) -> Result<crate::__private::de::Content<'de>, Self::Error>
fn __deserialize_content_v1<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de, Value = crate::__private::de::Content<'de>>,
V: Visitor<'de, Value = crate::private::Content<'de>>,
{
self.deserialize_any(visitor)
}
@@ -1282,6 +1308,12 @@ pub trait Deserializer<'de>: Sized {
/// }
/// }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Visitor<'de>` is not satisfied",
)
)]
pub trait Visitor<'de>: Sized {
/// The value produced by this visitor.
type Value;
@@ -1374,7 +1406,7 @@ pub trait Visitor<'de>: Sized {
E: Error,
{
let mut buf = [0u8; 58];
let mut writer = format::Buf::new(&mut buf);
let mut writer = crate::format::Buf::new(&mut buf);
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
Err(Error::invalid_type(
Unexpected::Other(writer.as_str()),
@@ -1436,7 +1468,7 @@ pub trait Visitor<'de>: Sized {
E: Error,
{
let mut buf = [0u8; 57];
let mut writer = format::Buf::new(&mut buf);
let mut writer = crate::format::Buf::new(&mut buf);
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
Err(Error::invalid_type(
Unexpected::Other(writer.as_str()),
@@ -1708,6 +1740,12 @@ pub trait Visitor<'de>: Sized {
/// implementation of `SeqAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::SeqAccess<'de>` is not satisfied",
)
)]
pub trait SeqAccess<'de> {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1742,7 +1780,7 @@ pub trait SeqAccess<'de> {
}
}
impl<'de, 'a, A> SeqAccess<'de> for &'a mut A
impl<'de, A> SeqAccess<'de> for &mut A
where
A: ?Sized + SeqAccess<'de>,
{
@@ -1790,6 +1828,12 @@ where
/// implementation of `MapAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::MapAccess<'de>` is not satisfied",
)
)]
pub trait MapAccess<'de> {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1895,7 +1939,7 @@ pub trait MapAccess<'de> {
}
}
impl<'de, 'a, A> MapAccess<'de> for &'a mut A
impl<'de, A> MapAccess<'de> for &mut A
where
A: ?Sized + MapAccess<'de>,
{
@@ -1982,6 +2026,12 @@ where
/// implementation of `EnumAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::EnumAccess<'de>` is not satisfied",
)
)]
pub trait EnumAccess<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -2029,6 +2079,12 @@ pub trait EnumAccess<'de>: Sized {
/// implementation of `VariantAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::VariantAccess<'de>` is not satisfied",
)
)]
pub trait VariantAccess<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization. Must match the error type of our `EnumAccess`.
@@ -24,7 +24,8 @@
use crate::lib::*;
use self::private::{First, Second};
use crate::de::{self, size_hint, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
use crate::private::size_hint;
use crate::ser;
////////////////////////////////////////////////////////////////////////////////
@@ -175,6 +176,17 @@ where
}
}
impl<'de, E> IntoDeserializer<'de, E> for UnitDeserializer<E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<E> Debug for UnitDeserializer<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.debug_struct("UnitDeserializer").finish()
@@ -225,6 +237,18 @@ where
}
}
#[cfg(feature = "unstable")]
impl<'de, E> IntoDeserializer<'de, E> for NeverDeserializer<E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
////////////////////////////////////////////////////////////////////////////////
macro_rules! primitive_deserializer {
@@ -279,6 +303,17 @@ macro_rules! primitive_deserializer {
}
}
impl<'de, E> IntoDeserializer<'de, E> for $name<E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<E> Debug for $name<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
@@ -369,6 +404,17 @@ where
}
}
impl<'de, E> IntoDeserializer<'de, E> for U32Deserializer<E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, E> de::EnumAccess<'de> for U32Deserializer<E>
where
E: de::Error,
@@ -458,6 +504,17 @@ where
}
}
impl<'de, 'a, E> IntoDeserializer<'de, E> for StrDeserializer<'a, E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
where
E: de::Error,
@@ -537,6 +594,17 @@ where
}
}
impl<'de, E> IntoDeserializer<'de, E> for BorrowedStrDeserializer<'de, E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E>
where
E: de::Error,
@@ -640,6 +708,18 @@ where
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> IntoDeserializer<'de, E> for StringDeserializer<E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> de::EnumAccess<'de> for StringDeserializer<E>
where
@@ -748,6 +828,18 @@ where
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> IntoDeserializer<'de, E> for CowStrDeserializer<'a, E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
where
@@ -825,6 +917,17 @@ where
}
}
impl<'de, 'a, E> IntoDeserializer<'de, E> for BytesDeserializer<'a, E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'a, E> Debug for BytesDeserializer<'a, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
@@ -873,6 +976,17 @@ where
}
}
impl<'de, E> IntoDeserializer<'de, E> for BorrowedBytesDeserializer<'de, E>
where
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
@@ -952,6 +1066,19 @@ where
}
}
impl<'de, I, T, E> IntoDeserializer<'de, E> for SeqDeserializer<I, E>
where
I: Iterator<Item = T>,
T: IntoDeserializer<'de, E>,
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, I, T, E> de::SeqAccess<'de> for SeqDeserializer<I, E>
where
I: Iterator<Item = T>,
@@ -1083,6 +1210,17 @@ where
}
}
impl<'de, A> IntoDeserializer<'de, A::Error> for SeqAccessDeserializer<A>
where
A: de::SeqAccess<'de>,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer that iterates over a map.
@@ -1197,6 +1335,21 @@ where
}
}
impl<'de, I, E> IntoDeserializer<'de, E> for MapDeserializer<'de, I, E>
where
I: Iterator,
I::Item: private::Pair,
First<I::Item>: IntoDeserializer<'de, E>,
Second<I::Item>: IntoDeserializer<'de, E>,
E: de::Error,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, I, E> de::MapAccess<'de> for MapDeserializer<'de, I, E>
where
I: Iterator,
@@ -1498,6 +1651,17 @@ where
}
}
impl<'de, A> IntoDeserializer<'de, A::Error> for MapAccessDeserializer<A>
where
A: de::MapAccess<'de>,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
where
A: de::MapAccess<'de>,
@@ -1551,6 +1715,17 @@ where
}
}
impl<'de, A> IntoDeserializer<'de, A::Error> for EnumAccessDeserializer<A>
where
A: de::EnumAccess<'de>,
{
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
////////////////////////////////////////////////////////////////////////////////
mod private {
+121
View File
@@ -0,0 +1,121 @@
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The `serde_core` crate contains Serde's trait definitions with **no support
//! for #\[derive()\]**.
//!
//! In crates that derive an implementation of `Serialize` or `Deserialize`, you
//! must depend on the [`serde`] crate, not `serde_core`.
//!
//! [`serde`]: https://crates.io/crates/serde
//!
//! In crates that handwrite implementations of Serde traits, or only use them
//! as trait bounds, depending on `serde_core` is permitted. But `serde`
//! re-exports all of these traits and can be used for this use case too. If in
//! doubt, disregard `serde_core` and always use `serde`.
//!
//! Crates that depend on `serde_core` instead of `serde` are able to compile in
//! parallel with `serde_derive` even when `serde`'s "derive" feature is turned on,
//! as shown in the following build timings.
//!
//! <br>
//!
//! <table>
//! <tr><td align="center">When <code>serde_json</code> depends on <code>serde</code></td></tr>
//! <tr><td><img src="https://github.com/user-attachments/assets/78dc179c-6ab1-4059-928c-1474b0d9d0bb"></td></tr>
//! </table>
//!
//! <br>
//!
//! <table>
//! <tr><td align="center">When <code>serde_json</code> depends on <code>serde_core</code></td></tr>
//! <tr><td><img src="https://github.com/user-attachments/assets/6b6cff5e-3e45-4ac7-9db1-d99ee8b9f5f7"></td></tr>
//! </table>
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde_core/1.0.228")]
// 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(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(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
// Ignored clippy and clippy_pedantic lints
#![allow(
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
clippy::unnested_or_patterns,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
clippy::semicolon_if_nothing_returned,
// not available in our oldest supported compiler
clippy::empty_enums,
clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
// integer and float ser/de requires these sorts of casts
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
// things are often more readable this way
clippy::cast_lossless,
clippy::module_name_repetitions,
clippy::single_match_else,
clippy::type_complexity,
clippy::use_self,
clippy::zero_prefixed_literal,
// correctly used
clippy::derive_partial_eq_without_eq,
clippy::enum_glob_use,
clippy::explicit_auto_deref,
clippy::incompatible_msrv,
clippy::let_underscore_untyped,
clippy::map_err_ignore,
clippy::new_without_default,
clippy::result_unit_err,
clippy::wildcard_imports,
// not practical
clippy::needless_pass_by_value,
clippy::similar_names,
clippy::too_many_lines,
// preference
clippy::doc_markdown,
clippy::elidable_lifetime_names,
clippy::needless_lifetimes,
clippy::unseparated_literal_suffix,
// false positive
clippy::needless_doctest_main,
// noisy
clippy::missing_errors_doc,
clippy::must_use_candidate,
)]
// Restrictions
#![deny(clippy::question_mark_used)]
// Rustc lints.
#![deny(missing_docs, unused_imports)]
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "alloc")]
extern crate alloc;
#[macro_use]
mod crate_root;
#[macro_use]
mod macros;
crate_root!();
#[macro_export]
#[doc(hidden)]
macro_rules! __require_serde_not_serde_core {
() => {
::core::compile_error!(
"Serde derive requires a dependency on the serde crate, not serde_core"
);
};
}
@@ -1,7 +1,6 @@
// Super explicit first paragraph because this shows up at the top level and
// trips up people who are just looking for basic Serialize / Deserialize
// documentation.
//
/// Helper macro when implementing the `Deserializer` part of a new data format
/// for Serde.
///
@@ -104,9 +103,9 @@
/// # }
/// ```
///
/// [`Deserializer`]: trait.Deserializer.html
/// [`Visitor`]: de/trait.Visitor.html
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
/// [`Deserializer`]: crate::Deserializer
/// [`Visitor`]: crate::de::Visitor
/// [`Deserializer::deserialize_any`]: crate::Deserializer::deserialize_any
#[macro_export(local_inner_macros)]
macro_rules! forward_to_deserialize_any {
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
+39
View File
@@ -0,0 +1,39 @@
use crate::lib::*;
// Used from generated code to buffer the contents of the Deserializer when
// deserializing untagged enums and internally tagged enums.
//
// Not public API. Use serde-value instead.
//
// Obsoleted by format-specific buffer types (https://github.com/serde-rs/serde/pull/2912).
#[doc(hidden)]
pub enum Content<'de> {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Char(char),
String(String),
Str(&'de str),
ByteBuf(Vec<u8>),
Bytes(&'de [u8]),
None,
Some(Box<Content<'de>>),
Unit,
Newtype(Box<Content<'de>>),
Seq(Vec<Content<'de>>),
Map(Vec<(Content<'de>, Content<'de>)>),
}
@@ -8,6 +8,7 @@ use crate::ser;
#[derive(Debug)]
pub struct Error;
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl ser::Error for Error {
fn custom<T>(_: T) -> Self
where
@@ -18,12 +19,14 @@ impl ser::Error for Error {
}
#[cfg(feature = "std")]
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl error::Error for Error {
fn description(&self) -> &str {
unimplemented!()
}
}
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl Display for Error {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
+21
View File
@@ -0,0 +1,21 @@
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
mod content;
mod seed;
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
#[doc(hidden)]
pub mod doc;
#[doc(hidden)]
pub mod size_hint;
#[doc(hidden)]
pub mod string;
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
#[doc(hidden)]
pub use self::content::Content;
#[doc(hidden)]
pub use self::seed::InPlaceSeed;
#[doc(hidden)]
pub use crate::lib::result::Result;
@@ -5,6 +5,7 @@ use crate::de::{Deserialize, DeserializeSeed, Deserializer};
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
where
T: Deserialize<'de>,
@@ -1,3 +1,4 @@
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::lib::*;
pub fn from_bounds<I>(iter: &I) -> Option<usize>
+23
View File
@@ -0,0 +1,23 @@
use crate::lib::*;
#[cfg(any(feature = "std", feature = "alloc"))]
#[doc(hidden)]
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> {
String::from_utf8_lossy(bytes)
}
// The generated code calls this like:
//
// let value = &_serde::__private::from_utf8_lossy(bytes);
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
//
// so it is okay for the return type to be different from the std case as long
// as the above works.
#[cfg(not(any(feature = "std", feature = "alloc")))]
#[doc(hidden)]
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
// Three unicode replacement characters if it fails. They look like a
// white-on-black question mark. The user will recognize it as invalid
// UTF-8.
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
}
@@ -35,7 +35,7 @@ macro_rules! fmt_primitives {
/// }
/// }
/// ```
impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
impl<'a> Serializer for &mut fmt::Formatter<'a> {
type Ok = ();
type Error = fmt::Error;
type SerializeSeq = Impossible<(), fmt::Error>;
@@ -185,11 +185,10 @@ where
}
}
#[cfg(not(no_relaxed_trait_bounds))]
macro_rules! seq_impl {
(
$(#[$attr:meta])*
$ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>
$ty:ident <T $(, $typaram:ident : $bound:ident)*>
) => {
$(#[$attr])*
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
@@ -207,45 +206,22 @@ macro_rules! seq_impl {
}
}
#[cfg(no_relaxed_trait_bounds)]
macro_rules! seq_impl {
(
$(#[$attr:meta])*
$ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>
) => {
$(#[$attr])*
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
where
T: Serialize $(+ $tbound1 $(+ $tbound2)*)*,
$($typaram: $bound,)*
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq(self)
}
}
}
seq_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BinaryHeap<T>
}
seq_impl! {
#[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(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
BTreeSet<T: Ord>
BTreeSet<T>
}
seq_impl! {
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
HashSet<T: Eq + Hash, H: BuildHasher>
HashSet<T, H: BuildHasher>
}
seq_impl! {
@@ -445,7 +421,6 @@ tuple_impls! {
////////////////////////////////////////////////////////////////////////////////
#[cfg(not(no_relaxed_trait_bounds))]
macro_rules! map_impl {
(
$(#[$attr:meta])*
@@ -468,30 +443,6 @@ macro_rules! map_impl {
}
}
#[cfg(no_relaxed_trait_bounds)]
macro_rules! map_impl {
(
$(#[$attr:meta])*
$ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)*>
) => {
$(#[$attr])*
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
where
K: Serialize $(+ $kbound1 $(+ $kbound2)*)*,
V: Serialize,
$($typaram: $bound,)*
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_map(self)
}
}
}
}
map_impl! {
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
@@ -631,16 +582,6 @@ macro_rules! nonzero_integers {
}
}
nonzero_integers! {
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize,
}
#[cfg(not(no_num_nonzero_signed))]
nonzero_integers! {
NonZeroI8,
NonZeroI16,
@@ -648,6 +589,12 @@ nonzero_integers! {
NonZeroI64,
NonZeroI128,
NonZeroIsize,
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize,
}
impl<T> Serialize for Cell<T>
@@ -713,6 +660,8 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "result")]
#[cfg_attr(docsrs, doc(cfg(feature = "result")))]
impl<T, E> Serialize for Result<T, E>
where
T: Serialize,
@@ -773,28 +722,17 @@ impl Serialize for SystemTime {
/// statically known to never have more than a constant `MAX_LEN` bytes.
///
/// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes.
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
macro_rules! serialize_display_bounded_length {
($value:expr, $max:expr, $serializer:expr) => {{
let mut buffer = [0u8; $max];
let remaining_len = {
let mut remaining = &mut buffer[..];
write!(remaining, "{}", $value).unwrap();
remaining.len()
};
let written_len = buffer.len() - remaining_len;
let written = &buffer[..written_len];
// write! only provides fmt::Formatter to Display implementations, which
// has methods write_str and write_char but no method to write arbitrary
// bytes. Therefore `written` must be valid UTF-8.
let written_str = str::from_utf8(written).expect("must be valid UTF-8");
$serializer.serialize_str(written_str)
let mut writer = crate::format::Buf::new(&mut buffer);
write!(&mut writer, "{}", $value).unwrap();
$serializer.serialize_str(writer.as_str())
}};
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -818,7 +756,7 @@ impl Serialize for net::IpAddr {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
const DEC_DIGITS_LUT: &[u8] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
@@ -826,7 +764,7 @@ const DEC_DIGITS_LUT: &[u8] = b"\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
#[inline]
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
if n >= 100 {
@@ -847,7 +785,7 @@ fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_net)))]
#[test]
fn test_format_u8() {
let mut i = 0u8;
@@ -864,8 +802,7 @@ fn test_format_u8() {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::Ipv4Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -889,8 +826,7 @@ impl Serialize for net::Ipv4Addr {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::Ipv6Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -906,8 +842,7 @@ impl Serialize for net::Ipv6Addr {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::SocketAddr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -931,8 +866,7 @@ impl Serialize for net::SocketAddr {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::SocketAddrV4 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -948,8 +882,7 @@ impl Serialize for net::SocketAddrV4 {
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(any(feature = "std", not(no_core_net)))]
impl Serialize for net::SocketAddrV6 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -17,7 +17,7 @@ use crate::ser::{
///
/// ```edition2021
/// # use serde::ser::{Serializer, Impossible};
/// # use serde::__private::doc::Error;
/// # use serde_core::__private::doc::Error;
/// #
/// # struct MySerializer;
/// #
@@ -41,7 +41,7 @@ use crate::ser::{
/// }
///
/// /* other Serializer methods */
/// # serde::__serialize_unimplemented! {
/// # serde_core::__serialize_unimplemented! {
/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes none some
/// # unit unit_struct unit_variant newtype_struct newtype_variant
/// # tuple tuple_struct tuple_variant map struct struct_variant
@@ -49,14 +49,14 @@ use crate::ser::{
/// }
/// ```
///
/// [`Serializer`]: trait.Serializer.html
/// [`SerializeSeq`]: trait.SerializeSeq.html
/// [`SerializeTuple`]: trait.SerializeTuple.html
/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html
/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html
/// [`SerializeMap`]: trait.SerializeMap.html
/// [`SerializeStruct`]: trait.SerializeStruct.html
/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html
/// [`Serializer`]: crate::Serializer
/// [`SerializeSeq`]: crate::ser::SerializeSeq
/// [`SerializeTuple`]: crate::ser::SerializeTuple
/// [`SerializeTupleStruct`]: crate::ser::SerializeTupleStruct
/// [`SerializeTupleVariant`]: crate::ser::SerializeTupleVariant
/// [`SerializeMap`]: crate::ser::SerializeMap
/// [`SerializeStruct`]: crate::ser::SerializeStruct
/// [`SerializeStructVariant`]: crate::ser::SerializeStructVariant
pub struct Impossible<Ok, Error> {
void: Void,
ok: PhantomData<Ok>,
@@ -97,8 +97,8 @@
//!
//! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
//! [`Serialize`]: ../trait.Serialize.html
//! [`Serializer`]: ../trait.Serializer.html
//! [`Serialize`]: crate::Serialize
//! [`Serializer`]: crate::Serializer
//! [`postcard`]: https://github.com/jamesmunns/postcard
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
//! [`serde_derive`]: https://crates.io/crates/serde_derive
@@ -115,10 +115,10 @@ mod impossible;
pub use self::impossible::Impossible;
#[cfg(not(any(feature = "std", feature = "unstable")))]
#[cfg(all(not(feature = "std"), no_core_error))]
#[doc(no_inline)]
pub use crate::std_error::Error as StdError;
#[cfg(all(feature = "unstable", not(feature = "std")))]
#[cfg(not(any(feature = "std", no_core_error)))]
#[doc(no_inline)]
pub use core::error::Error as StdError;
#[cfg(feature = "std")]
@@ -139,6 +139,12 @@ macro_rules! declare_error_trait {
/// type appropriate for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::Error` is not satisfied",
)
)]
pub trait Error: Sized $(+ $($supertrait)::+)* {
/// Used when a [`Serialize`] implementation encounters any error
/// while serializing a type.
@@ -173,8 +179,8 @@ macro_rules! declare_error_trait {
/// }
/// ```
///
/// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
/// [`Serialize`]: ../trait.Serialize.html
/// [`Path`]: std::path::Path
/// [`Serialize`]: crate::Serialize
fn custom<T>(msg: T) -> Self
where
T: Display;
@@ -218,6 +224,9 @@ declare_error_trait!(Error: Sized + Debug + Display);
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
// Prevents `serde_core::ser::Serialize` appearing in the error message
// in projects with no direct dependency on serde_core.
message = "the trait bound `{Self}: serde::Serialize` is not satisfied",
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",
)
@@ -337,6 +346,12 @@ pub trait Serialize {
/// a basic JSON `Serializer`.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::Serializer` is not satisfied",
)
)]
pub trait Serializer: Sized {
/// The output type produced by this `Serializer` during successful
/// serialization. Most serializers that produce text or binary output
@@ -345,7 +360,7 @@ pub trait Serializer: Sized {
/// in-memory data structures may be simplified by using `Ok` to propagate
/// the data structure around.
///
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`io::Write`]: std::io::Write
type Ok;
/// The error type when some error occurs during serialization.
@@ -398,7 +413,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for bool {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -420,7 +435,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for i8 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -442,7 +457,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for i16 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -464,7 +479,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for i32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -482,7 +497,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for i64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -500,7 +515,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for i128 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -527,7 +542,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for u8 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -549,7 +564,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for u16 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -571,7 +586,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for u32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -589,7 +604,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for u64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -607,7 +622,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for u128 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -634,7 +649,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for f32 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -652,7 +667,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for f64 {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -673,7 +688,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for char {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -691,7 +706,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for str {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -714,7 +729,7 @@ pub trait Serializer: Sized {
///
/// ```edition2021
/// # use serde::ser::{Serializer, SerializeSeq};
/// # use serde::__private::doc::Error;
/// # use serde_core::__private::doc::Error;
/// #
/// # struct MySerializer;
/// #
@@ -730,7 +745,7 @@ pub trait Serializer: Sized {
/// seq.end()
/// }
/// #
/// # serde::__serialize_unimplemented! {
/// # serde_core::__serialize_unimplemented! {
/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str none some
/// # unit unit_struct unit_variant newtype_struct newtype_variant
/// # seq tuple tuple_struct tuple_variant map struct struct_variant
@@ -769,7 +784,7 @@ pub trait Serializer: Sized {
/// # fn main() {}
/// ```
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`None`]: core::option::Option::None
fn serialize_none(self) -> Result<Self::Ok, Self::Error>;
/// Serialize a [`Some(T)`] value.
@@ -802,7 +817,7 @@ pub trait Serializer: Sized {
/// # fn main() {}
/// ```
///
/// [`Some(T)`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
/// [`Some(T)`]: core::option::Option::Some
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize;
@@ -812,7 +827,7 @@ pub trait Serializer: Sized {
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
/// # serde_core::__private_serialize!();
/// #
/// impl Serialize for () {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -1353,8 +1368,7 @@ pub trait Serializer: Sized {
/// }
/// ```
///
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// [`serialize_str`]: #tymethod.serialize_str
/// [`serialize_str`]: Self::serialize_str
#[cfg(any(feature = "std", feature = "alloc"))]
fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
@@ -1495,6 +1509,12 @@ pub trait Serializer: Sized {
/// implementation of `SerializeSeq` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeSeq` is not satisfied",
)
)]
pub trait SerializeSeq {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1595,6 +1615,12 @@ pub trait SerializeSeq {
/// implementation of `SerializeTuple` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTuple` is not satisfied",
)
)]
pub trait SerializeTuple {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1640,6 +1666,12 @@ pub trait SerializeTuple {
/// implementation of `SerializeTupleStruct` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTupleStruct` is not satisfied",
)
)]
pub trait SerializeTupleStruct {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1698,6 +1730,12 @@ pub trait SerializeTupleStruct {
/// implementation of `SerializeTupleVariant` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTupleVariant` is not satisfied",
)
)]
pub trait SerializeTupleVariant {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1764,6 +1802,12 @@ pub trait SerializeTupleVariant {
/// implementation of `SerializeMap` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeMap` is not satisfied",
)
)]
pub trait SerializeMap {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1805,9 +1849,9 @@ pub trait SerializeMap {
/// care about performance or are not able to optimize `serialize_entry` any
/// better than this.
///
/// [`Serialize`]: ../trait.Serialize.html
/// [`serialize_key`]: #tymethod.serialize_key
/// [`serialize_value`]: #tymethod.serialize_value
/// [`Serialize`]: crate::Serialize
/// [`serialize_key`]: Self::serialize_key
/// [`serialize_value`]: Self::serialize_value
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
where
K: ?Sized + Serialize,
@@ -1854,6 +1898,12 @@ pub trait SerializeMap {
/// implementation of `SerializeStruct` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeStruct` is not satisfied",
)
)]
pub trait SerializeStruct {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1918,6 +1968,12 @@ pub trait SerializeStruct {
/// implementation of `SerializeStructVariant` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeStructVariant` is not satisfied",
)
)]
pub trait SerializeStructVariant {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -42,7 +42,7 @@ use crate::lib::{Debug, Display};
/// ```
pub trait Error: Debug + Display {
/// The underlying cause of this error, if any.
fn source(&self) -> Option<&(Error + 'static)> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
+11 -4
View File
@@ -1,18 +1,18 @@
[package]
name = "serde_derive"
version = "1.0.209"
version = "1.0.228"
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"
edition = "2021"
exclude = ["build.rs"]
homepage = "https://serde.rs"
keywords = ["serde", "serialization", "no_std", "derive"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.56"
rust-version = "1.68"
[features]
default = []
@@ -32,4 +32,11 @@ serde = { version = "1", path = "../serde" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
rustdoc-args = [
"--generate-link-to-definition",
"--generate-macro-expansion",
"--extern-html-root-url=core=https://doc.rust-lang.org",
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
"--extern-html-root-url=std=https://doc.rust-lang.org",
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
]
+3 -1
View File
@@ -227,7 +227,9 @@ pub fn with_bound(
match bound {
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
syn::TypeParamBound::Lifetime(_)
| syn::TypeParamBound::PreciseCapture(_)
| syn::TypeParamBound::Verbatim(_) => {}
_ => {}
}
}
+136 -2332
View File
File diff suppressed because it is too large Load Diff
+96
View File
@@ -0,0 +1,96 @@
use crate::de::enum_adjacently;
use crate::de::enum_externally;
use crate::de::enum_internally;
use crate::de::enum_untagged;
use crate::de::identifier;
use crate::de::{field_i, FieldWithAliases, Parameters};
use crate::fragment::{Expr, Fragment, Stmts};
use crate::internals::ast::Variant;
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::quote;
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}`
pub(super) fn deserialize(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
// The variants have already been checked (in ast.rs) that all untagged variants appear at the end
match variants.iter().position(|var| var.attrs.untagged()) {
Some(variant_idx) => {
let (tagged, untagged) = variants.split_at(variant_idx);
let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
// Ignore any error associated with non-untagged deserialization so that we
// can fall through to the untagged variants. This may be infallible so we
// need to provide the error type.
let first_attempt = quote! {
if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() {
return _serde::#private::Ok(__ok);
}
};
enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt))
}
None => deserialize_homogeneous_enum(params, variants, cattrs),
}
}
fn deserialize_homogeneous_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
match cattrs.tag() {
attr::TagType::External => enum_externally::deserialize(params, variants, cattrs),
attr::TagType::Internal { tag } => {
enum_internally::deserialize(params, variants, cattrs, tag)
}
attr::TagType::Adjacent { tag, content } => {
enum_adjacently::deserialize(params, variants, cattrs, tag, content)
}
attr::TagType::None => enum_untagged::deserialize(params, variants, cattrs, None),
}
}
pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
let deserialized_variants = variants
.iter()
.enumerate()
.filter(|&(_i, variant)| !variant.attrs.skip_deserializing());
let fallthrough = deserialized_variants
.clone()
.find(|(_i, variant)| variant.attrs.other())
.map(|(i, _variant)| {
let ignore_variant = field_i(i);
quote!(_serde::#private::Ok(__Field::#ignore_variant))
});
let variants_stmt = {
let variant_names = deserialized_variants
.clone()
.flat_map(|(_i, variant)| variant.attrs.aliases());
quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
};
let deserialized_variants: Vec<_> = deserialized_variants
.map(|(i, variant)| FieldWithAliases {
ident: field_i(i),
aliases: variant.attrs.aliases(),
})
.collect();
let variant_visitor = Stmts(identifier::deserialize_generated(
&deserialized_variants,
false, // variant identifiers do not depend on the presence of flatten fields
true,
None,
fallthrough,
));
(variants_stmt, variant_visitor)
}
+325
View File
@@ -0,0 +1,325 @@
//! Deserialization for adjacently tagged enums:
//!
//! ```ignore
//! #[serde(tag = "...", content = "...")]
//! enum Enum {}
//! ```
use crate::de::enum_;
use crate::de::enum_untagged;
use crate::de::{field_i, Parameters};
use crate::fragment::{Fragment, Match};
use crate::internals::ast::{Style, Variant};
use crate::internals::attr;
use crate::private;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes
pub(super) fn deserialize(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
tag: &str,
content: &str,
) -> Fragment {
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
let variant_arms: &Vec<_> = &variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| {
let variant_index = field_i(i);
let block = Match(enum_untagged::deserialize_variant(params, variant, cattrs));
quote! {
__Field::#variant_index => #block
}
})
.collect();
let rust_name = params.type_name();
let expecting = format!("adjacently tagged enum {}", rust_name);
let expecting = cattrs.expecting().unwrap_or(&expecting);
let type_name = cattrs.name().deserialize_name();
let deny_unknown_fields = cattrs.deny_unknown_fields();
// If unknown fields are allowed, we pick the visitor that can step over
// those. Otherwise we pick the visitor that fails on unknown keys.
let field_visitor_ty = if deny_unknown_fields {
quote! { _serde::#private::de::TagOrContentFieldVisitor }
} else {
quote! { _serde::#private::de::TagContentOtherFieldVisitor }
};
let mut missing_content = quote! {
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
};
let mut missing_content_fallthrough = quote!();
let missing_content_arms = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.filter_map(|(i, variant)| {
let variant_index = field_i(i);
let variant_ident = &variant.ident;
let arm = match variant.style {
Style::Unit => quote! {
_serde::#private::Ok(#this_value::#variant_ident)
},
Style::Newtype if variant.attrs.deserialize_with().is_none() => {
let span = variant.original.span();
let func = quote_spanned!(span=> _serde::#private::de::missing_field);
quote! {
#func(#content).map(#this_value::#variant_ident)
}
}
_ => {
missing_content_fallthrough = quote!(_ => #missing_content);
return None;
}
};
Some(quote! {
__Field::#variant_index => #arm,
})
})
.collect::<Vec<_>>();
if !missing_content_arms.is_empty() {
missing_content = quote! {
match __field {
#(#missing_content_arms)*
#missing_content_fallthrough
}
};
}
// Advance the map by one key, returning early in case of error.
let next_key = quote! {
_serde::de::MapAccess::next_key_seed(&mut __map, #field_visitor_ty {
tag: #tag,
content: #content,
})?
};
let variant_from_map = quote! {
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> {
enum_name: #rust_name,
variants: VARIANTS,
fields_enum: _serde::#private::PhantomData
})?
};
// When allowing unknown fields, we want to transparently step through keys
// we don't care about until we find `tag`, `content`, or run out of keys.
let next_relevant_key = if deny_unknown_fields {
next_key
} else {
quote!({
let mut __rk : _serde::#private::Option<_serde::#private::de::TagOrContentField> = _serde::#private::None;
while let _serde::#private::Some(__k) = #next_key {
match __k {
_serde::#private::de::TagContentOtherField::Other => {
let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
continue;
},
_serde::#private::de::TagContentOtherField::Tag => {
__rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag);
break;
}
_serde::#private::de::TagContentOtherField::Content => {
__rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Content);
break;
}
}
}
__rk
})
};
// Step through remaining keys, looking for duplicates of previously-seen
// keys. When unknown fields are denied, any key that isn't a duplicate will
// at this point immediately produce an error.
let visit_remaining_keys = quote! {
match #next_relevant_key {
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
}
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content))
}
_serde::#private::None => _serde::#private::Ok(__ret),
}
};
let finish_content_then_tag = if variant_arms.is_empty() {
quote! {
match #variant_from_map {}
}
} else {
quote! {
let __seed = __Seed {
variant: #variant_from_map,
marker: _serde::#private::PhantomData,
lifetime: _serde::#private::PhantomData,
};
let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content);
let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?;
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
};
quote_block! {
#variant_visitor
#variants_stmt
#[doc(hidden)]
struct __Seed #de_impl_generics #where_clause {
variant: __Field,
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
where
__D: _serde::Deserializer<#delife>,
{
match self.variant {
#(#variant_arms)*
}
}
}
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::MapAccess<#delife>,
{
// Visit the first relevant key.
match #next_relevant_key {
// First key is the tag.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
// Parse the tag.
let __field = #variant_from_map;
// Visit the second key.
match #next_relevant_key {
// Second key is a duplicate of the tag.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
}
// Second key is the content.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
let __ret = _serde::de::MapAccess::next_value_seed(&mut __map,
__Seed {
variant: __field,
marker: _serde::#private::PhantomData,
lifetime: _serde::#private::PhantomData,
})?;
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
// There is no second key; might be okay if the we have a unit variant.
_serde::#private::None => #missing_content
}
}
// First key is the content.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
// Buffer up the content.
let __content = _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?;
// Visit the second key.
match #next_relevant_key {
// Second key is the tag.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
#finish_content_then_tag
}
// Second key is a duplicate of the content.
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content))
}
// There is no second key.
_serde::#private::None => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag))
}
}
}
// There is no first key.
_serde::#private::None => {
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag))
}
}
}
fn visit_seq<__A>(self, mut __seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
// Visit the first element - the tag.
match _serde::de::SeqAccess::next_element(&mut __seq) {
_serde::#private::Ok(_serde::#private::Some(__variant)) => {
// Visit the second element - the content.
match _serde::de::SeqAccess::next_element_seed(
&mut __seq,
__Seed {
variant: __variant,
marker: _serde::#private::PhantomData,
lifetime: _serde::#private::PhantomData,
},
) {
_serde::#private::Ok(_serde::#private::Some(__ret)) => _serde::#private::Ok(__ret),
// There is no second element.
_serde::#private::Ok(_serde::#private::None) => {
_serde::#private::Err(_serde::de::Error::invalid_length(1, &self))
}
_serde::#private::Err(__err) => _serde::#private::Err(__err),
}
}
// There is no first element.
_serde::#private::Ok(_serde::#private::None) => {
_serde::#private::Err(_serde::de::Error::invalid_length(0, &self))
}
_serde::#private::Err(__err) => _serde::#private::Err(__err),
}
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content];
_serde::Deserializer::deserialize_struct(
__deserializer,
#type_name,
FIELDS,
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
},
)
}
}
+213
View File
@@ -0,0 +1,213 @@
//! Deserialization for externally tagged enums:
//!
//! ```ignore
//! enum Enum {}
//! ```
use crate::de::enum_;
use crate::de::struct_;
use crate::de::tuple;
use crate::de::{
expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with,
wrap_deserialize_with, Parameters, StructForm, TupleForm,
};
use crate::fragment::{Expr, Fragment, Match};
use crate::internals::ast::{Field, Style, Variant};
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes
pub(super) fn deserialize(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let this_type = &params.this_type;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let type_name = cattrs.name().deserialize_name();
let expecting = format!("enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
// Match arms to extract a variant from a string
let variant_arms = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| {
let variant_name = field_i(i);
let block = Match(deserialize_externally_tagged_variant(
params, variant, cattrs,
));
quote! {
_serde::#private::Ok((__Field::#variant_name, __variant)) => #block
}
});
let all_skipped = variants
.iter()
.all(|variant| variant.attrs.skip_deserializing());
let match_variant = if all_skipped {
// This is an empty enum like `enum Impossible {}` or an enum in which
// all variants have `#[serde(skip_deserializing)]`.
quote! {
// FIXME: Once feature(exhaustive_patterns) is stable:
// let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data);
// _serde::#private::Err(__err)
_serde::#private::Result::map(
_serde::de::EnumAccess::variant::<__Field>(__data),
|(__impossible, _)| match __impossible {})
}
} else {
quote! {
match _serde::de::EnumAccess::variant(__data) {
#(#variant_arms)*
_serde::#private::Err(__err) => _serde::#private::Err(__err),
}
}
};
quote_block! {
#variant_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::EnumAccess<#delife>,
{
#match_variant
}
}
#variants_stmt
_serde::Deserializer::deserialize_enum(
__deserializer,
#type_name,
VARIANTS,
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
},
)
}
}
fn deserialize_externally_tagged_variant(
params: &Parameters,
variant: &Variant,
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
return quote_block! {
#wrapper
_serde::#private::Result::map(
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
};
}
let variant_ident = &variant.ident;
match variant.style {
Style::Unit => {
let this_value = &params.this_value;
quote_block! {
_serde::de::VariantAccess::unit_variant(__variant)?;
_serde::#private::Ok(#this_value::#variant_ident)
}
}
Style::Newtype => deserialize_externally_tagged_newtype_variant(
variant_ident,
params,
&variant.fields[0],
cattrs,
),
Style::Tuple => tuple::deserialize(
params,
&variant.fields,
cattrs,
TupleForm::ExternallyTagged(variant_ident),
),
Style::Struct => struct_::deserialize(
params,
&variant.fields,
cattrs,
StructForm::ExternallyTagged(variant_ident),
),
}
}
fn wrap_deserialize_variant_with(
params: &Parameters,
variant: &Variant,
deserialize_with: &syn::ExprPath,
) -> (TokenStream, TokenStream, TokenStream) {
let field_tys = variant.fields.iter().map(|field| field.ty);
let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with);
let unwrap_fn = unwrap_to_variant_closure(params, variant, true);
(wrapper, wrapper_ty, unwrap_fn)
}
fn deserialize_externally_tagged_newtype_variant(
variant_ident: &syn::Ident,
params: &Parameters,
field: &Field,
cattrs: &attr::Container,
) -> Fragment {
let this_value = &params.this_value;
if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(field, cattrs));
return quote_block! {
_serde::de::VariantAccess::unit_variant(__variant)?;
_serde::#private::Ok(#this_value::#variant_ident(#default))
};
}
match field.attrs.deserialize_with() {
None => {
let field_ty = field.ty;
let span = field.original.span();
let func =
quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>);
quote_expr! {
_serde::#private::Result::map(#func(__variant), #this_value::#variant_ident)
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote_block! {
#wrapper
_serde::#private::Result::map(
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant),
|__wrapper| #this_value::#variant_ident(__wrapper.value))
}
}
}
}
+106
View File
@@ -0,0 +1,106 @@
//! Deserialization for internally tagged enums:
//!
//! ```ignore
//! #[serde(tag = "...")]
//! enum Enum {}
//! ```
use crate::de::enum_;
use crate::de::enum_untagged;
use crate::de::struct_;
use crate::de::{
effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm,
};
use crate::fragment::{Expr, Fragment, Match};
use crate::internals::ast::{Style, Variant};
use crate::internals::attr;
use crate::private;
use quote::quote;
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute
pub(super) fn deserialize(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
tag: &str,
) -> Fragment {
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
// Match arms to extract a variant from a string
let variant_arms = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| {
let variant_name = field_i(i);
let block = Match(deserialize_internally_tagged_variant(
params, variant, cattrs,
));
quote! {
__Field::#variant_name => #block
}
});
let expecting = format!("internally tagged enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
#variant_visitor
#variants_stmt
let (__tag, __content) = _serde::Deserializer::deserialize_any(
__deserializer,
_serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?;
let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content);
match __tag {
#(#variant_arms)*
}
}
}
// Generates significant part of the visit_seq and visit_map bodies of visitors
// for the variants of internally tagged enum.
fn deserialize_internally_tagged_variant(
params: &Parameters,
variant: &Variant,
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
return quote_block! {
_serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
};
}
let variant_ident = &variant.ident;
match effective_style(variant) {
Style::Unit => {
let this_value = &params.this_value;
let type_name = params.type_name();
let variant_name = variant.ident.to_string();
let default = variant.fields.first().map(|field| {
let default = Expr(expr_is_missing(field, cattrs));
quote!((#default))
});
quote_block! {
_serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?;
_serde::#private::Ok(#this_value::#variant_ident #default)
}
}
Style::Newtype => {
enum_untagged::deserialize_newtype_variant(variant_ident, params, &variant.fields[0])
}
Style::Struct => struct_::deserialize(
params,
&variant.fields,
cattrs,
StructForm::InternallyTagged(variant_ident),
),
Style::Tuple => unreachable!("checked in serde_derive_internals"),
}
}
+135
View File
@@ -0,0 +1,135 @@
//! Deserialization for untagged enums:
//!
//! ```ignore
//! #[serde(untagged)]
//! enum Enum {}
//! ```
use crate::de::struct_;
use crate::de::tuple;
use crate::de::{
effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm,
};
use crate::fragment::{Expr, Fragment};
use crate::internals::ast::{Field, Style, Variant};
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute
pub(super) fn deserialize(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
first_attempt: Option<TokenStream>,
) -> Fragment {
let attempts = variants
.iter()
.filter(|variant| !variant.attrs.skip_deserializing())
.map(|variant| Expr(deserialize_variant(params, variant, cattrs)));
// TODO this message could be better by saving the errors from the failed
// attempts. The heuristic used by TOML was to count the number of fields
// processed before an error, and use the error that happened after the
// largest number of fields. I'm not sure I like that. Maybe it would be
// better to save all the errors and combine them into one message that
// explains why none of the variants matched.
let fallthrough_msg = format!(
"data did not match any variant of untagged enum {}",
params.type_name()
);
let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
let private2 = private;
quote_block! {
let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?;
let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
#first_attempt
#(
if let _serde::#private2::Ok(__ok) = #attempts {
return _serde::#private2::Ok(__ok);
}
)*
_serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg))
}
}
// Also used by adjacently tagged enums
pub(super) fn deserialize_variant(
params: &Parameters,
variant: &Variant,
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
return quote_block! {
_serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
};
}
let variant_ident = &variant.ident;
match effective_style(variant) {
Style::Unit => {
let this_value = &params.this_value;
let type_name = params.type_name();
let variant_name = variant.ident.to_string();
let default = variant.fields.first().map(|field| {
let default = Expr(expr_is_missing(field, cattrs));
quote!((#default))
});
quote_expr! {
match _serde::Deserializer::deserialize_any(
__deserializer,
_serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name)
) {
_serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default),
_serde::#private::Err(__err) => _serde::#private::Err(__err),
}
}
}
Style::Newtype => deserialize_newtype_variant(variant_ident, params, &variant.fields[0]),
Style::Tuple => tuple::deserialize(
params,
&variant.fields,
cattrs,
TupleForm::Untagged(variant_ident),
),
Style::Struct => struct_::deserialize(
params,
&variant.fields,
cattrs,
StructForm::Untagged(variant_ident),
),
}
}
// Also used by internally tagged enums
// Implicitly (via `generate_variant`) used by adjacently tagged enums
pub(super) fn deserialize_newtype_variant(
variant_ident: &syn::Ident,
params: &Parameters,
field: &Field,
) -> Fragment {
let this_value = &params.this_value;
let field_ty = field.ty;
match field.attrs.deserialize_with() {
None => {
let span = field.original.span();
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
quote_expr! {
_serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident)
}
}
Some(path) => {
quote_block! {
let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer);
_serde::#private::Result::map(__value, #this_value::#variant_ident)
}
}
}
}
+477
View File
@@ -0,0 +1,477 @@
//! Deserialization of struct field identifiers and enum variant identifiers by
//! way of a Rust enum.
use crate::de::{FieldWithAliases, Parameters};
use crate::fragment::{Fragment, Stmts};
use crate::internals::ast::{Style, Variant};
use crate::internals::attr;
use crate::private;
use proc_macro2::{Literal, TokenStream};
use quote::{quote, ToTokens};
// Generates `Deserialize::deserialize` body for an enum with
// `serde(field_identifier)` or `serde(variant_identifier)` attribute.
pub(super) fn deserialize_custom(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let is_variant = match cattrs.identifier() {
attr::Identifier::Variant => true,
attr::Identifier::Field => false,
attr::Identifier::No => unreachable!(),
};
let this_type = params.this_type.to_token_stream();
let this_value = params.this_value.to_token_stream();
let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() {
let last_ident = &last.ident;
if last.attrs.other() {
// Process `serde(other)` attribute. It would always be found on the
// last variant (checked in `check_identifier`), so all preceding
// are ordinary variants.
let ordinary = &variants[..variants.len() - 1];
let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident));
(ordinary, Some(fallthrough), None)
} else if let Style::Newtype = last.style {
let ordinary = &variants[..variants.len() - 1];
let fallthrough = |value| {
quote! {
_serde::#private::Result::map(
_serde::Deserialize::deserialize(
_serde::#private::de::IdentifierDeserializer::from(#value)
),
#this_value::#last_ident)
}
};
(
ordinary,
Some(fallthrough(quote!(__value))),
Some(fallthrough(quote!(_serde::#private::de::Borrowed(
__value
)))),
)
} else {
(variants, None, None)
}
} else {
(variants, None, None)
};
let idents_aliases: Vec<_> = ordinary
.iter()
.map(|variant| FieldWithAliases {
ident: variant.ident.clone(),
aliases: variant.attrs.aliases(),
})
.collect();
let names = idents_aliases.iter().flat_map(|variant| variant.aliases);
let names_const = if fallthrough.is_some() {
None
} else if is_variant {
let variants = quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
};
Some(variants)
} else {
let fields = quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#names),* ];
};
Some(fields)
};
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let visitor_impl = Stmts(deserialize_identifier(
&this_value,
&idents_aliases,
is_variant,
fallthrough,
fallthrough_borrowed,
false,
cattrs.expecting(),
));
quote_block! {
#names_const
#[doc(hidden)]
struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
#visitor_impl
}
let __visitor = __FieldVisitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
};
_serde::Deserializer::deserialize_identifier(__deserializer, __visitor)
}
}
pub(super) fn deserialize_generated(
deserialized_fields: &[FieldWithAliases],
has_flatten: bool,
is_variant: bool,
ignore_variant: Option<TokenStream>,
fallthrough: Option<TokenStream>,
) -> Fragment {
let this_value = quote!(__Field);
let field_idents: &Vec<_> = &deserialized_fields
.iter()
.map(|field| &field.ident)
.collect();
let visitor_impl = Stmts(deserialize_identifier(
&this_value,
deserialized_fields,
is_variant,
fallthrough,
None,
!is_variant && has_flatten,
None,
));
let lifetime = if !is_variant && has_flatten {
Some(quote!(<'de>))
} else {
None
};
quote_block! {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field #lifetime {
#(#field_idents,)*
#ignore_variant
}
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field #lifetime;
#visitor_impl
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field #lifetime {
#[inline]
fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result<Self, __D::Error>
where
__D: _serde::Deserializer<'de>,
{
_serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
}
}
}
}
fn deserialize_identifier(
this_value: &TokenStream,
deserialized_fields: &[FieldWithAliases],
is_variant: bool,
fallthrough: Option<TokenStream>,
fallthrough_borrowed: Option<TokenStream>,
collect_other_fields: bool,
expecting: Option<&str>,
) -> Fragment {
let str_mapping = deserialized_fields.iter().map(|field| {
let ident = &field.ident;
let aliases = field.aliases;
let private2 = private;
// `aliases` also contains a main name
quote! {
#(
#aliases => _serde::#private2::Ok(#this_value::#ident),
)*
}
});
let bytes_mapping = deserialized_fields.iter().map(|field| {
let ident = &field.ident;
// `aliases` also contains a main name
let aliases = field
.aliases
.iter()
.map(|alias| Literal::byte_string(alias.value.as_bytes()));
let private2 = private;
quote! {
#(
#aliases => _serde::#private2::Ok(#this_value::#ident),
)*
}
});
let expecting = expecting.unwrap_or(if is_variant {
"variant identifier"
} else {
"field identifier"
});
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
None
} else {
Some(quote! {
let __value = &_serde::#private::from_utf8_lossy(__value);
})
};
let (
value_as_str_content,
value_as_borrowed_str_content,
value_as_bytes_content,
value_as_borrowed_bytes_content,
) = if collect_other_fields {
(
Some(quote! {
let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value));
}),
Some(quote! {
let __value = _serde::#private::de::Content::Str(__value);
}),
Some(quote! {
let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec());
}),
Some(quote! {
let __value = _serde::#private::de::Content::Bytes(__value);
}),
)
} else {
(None, None, None, None)
};
let fallthrough_arm_tokens;
let fallthrough_arm = if let Some(fallthrough) = &fallthrough {
fallthrough
} else if is_variant {
fallthrough_arm_tokens = quote! {
_serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
};
&fallthrough_arm_tokens
} else {
fallthrough_arm_tokens = quote! {
_serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS))
};
&fallthrough_arm_tokens
};
let visit_other = if collect_other_fields {
quote! {
fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value)))
}
fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value)))
}
fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value)))
}
fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value)))
}
fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value)))
}
fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value)))
}
fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value)))
}
fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value)))
}
fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value)))
}
fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value)))
}
fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value)))
}
fn visit_char<__E>(self, __value: char) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value)))
}
fn visit_unit<__E>(self) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit))
}
}
} else {
let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| {
let i = i as u64;
let ident = &field.ident;
quote!(#i => _serde::#private::Ok(#this_value::#ident))
});
let u64_fallthrough_arm_tokens;
let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough {
fallthrough
} else {
let index_expecting = if is_variant { "variant" } else { "field" };
let fallthrough_msg = format!(
"{} index 0 <= i < {}",
index_expecting,
deserialized_fields.len(),
);
u64_fallthrough_arm_tokens = quote! {
_serde::#private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&#fallthrough_msg,
))
};
&u64_fallthrough_arm_tokens
};
quote! {
fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(#u64_mapping,)*
_ => #u64_fallthrough_arm,
}
}
}
};
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields {
let str_mapping = str_mapping.clone();
let bytes_mapping = bytes_mapping.clone();
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm);
Some(quote! {
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(#str_mapping)*
_ => {
#value_as_borrowed_str_content
#fallthrough_borrowed_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(#bytes_mapping)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_borrowed_arm
}
}
}
})
} else {
None
};
quote_block! {
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#visit_other
fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(#str_mapping)*
_ => {
#value_as_str_content
#fallthrough_arm
}
}
}
fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(#bytes_mapping)*
_ => {
#bytes_to_str
#value_as_bytes_content
#fallthrough_arm
}
}
}
#visit_borrowed
}
}
+697
View File
@@ -0,0 +1,697 @@
use crate::de::identifier;
use crate::de::{
deserialize_seq, expr_is_missing, field_i, has_flatten, wrap_deserialize_field_with,
FieldWithAliases, Parameters, StructForm,
};
#[cfg(feature = "deserialize_in_place")]
use crate::de::{deserialize_seq_in_place, place_lifetime};
use crate::fragment::{Expr, Fragment, Match, Stmts};
use crate::internals::ast::Field;
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Generates `Deserialize::deserialize` body for a `struct Struct {...}`
pub(super) fn deserialize(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
form: StructForm,
) -> Fragment {
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly.
let construct = if params.has_getter {
let local = &params.local;
quote!(#local)
} else {
quote!(#this_value)
};
let type_path = match form {
StructForm::Struct => construct,
StructForm::ExternallyTagged(variant_ident)
| StructForm::InternallyTagged(variant_ident)
| StructForm::Untagged(variant_ident) => quote!(#construct::#variant_ident),
};
let expecting = match form {
StructForm::Struct => format!("struct {}", params.type_name()),
StructForm::ExternallyTagged(variant_ident)
| StructForm::InternallyTagged(variant_ident)
| StructForm::Untagged(variant_ident) => {
format!("struct variant {}::{}", params.type_name(), variant_ident)
}
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let deserialized_fields: Vec<_> = fields
.iter()
.enumerate()
// Skip fields that shouldn't be deserialized or that were flattened,
// so they don't appear in the storage in their literal form
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(i, field)| FieldWithAliases {
ident: field_i(i),
aliases: field.attrs.aliases(),
})
.collect();
let has_flatten = has_flatten(fields);
let field_visitor = deserialize_field_identifier(&deserialized_fields, 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 has_flatten => None,
_ => {
let mut_seq = if deserialized_fields.is_empty() {
quote!(_)
} else {
quote!(mut __seq)
};
let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, true, cattrs, expecting,
));
Some(quote! {
#[inline]
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
})
}
};
let visit_map = Stmts(deserialize_map(
&type_path,
params,
fields,
cattrs,
has_flatten,
));
let visitor_seed = match form {
StructForm::ExternallyTagged(..) if has_flatten => Some(quote! {
#[automatically_derived]
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
where
__D: _serde::Deserializer<#delife>,
{
_serde::Deserializer::deserialize_map(__deserializer, self)
}
}
}),
_ => None,
};
let fields_stmt = if has_flatten {
None
} else {
let field_names = deserialized_fields.iter().flat_map(|field| field.aliases);
Some(quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
})
};
let visitor_expr = quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
}
};
let dispatch = match form {
StructForm::Struct if has_flatten => quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
},
StructForm::Struct => {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
}
StructForm::ExternallyTagged(_) if has_flatten => quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
},
StructForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
},
StructForm::InternallyTagged(_) => quote! {
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
StructForm::Untagged(_) => quote! {
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
};
quote_block! {
#field_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#visit_seq
#[inline]
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::MapAccess<#delife>,
{
#visit_map
}
}
#visitor_seed
#fields_stmt
#dispatch
}
}
fn deserialize_map(
struct_path: &TokenStream,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
has_flatten: bool,
) -> Fragment {
// Create the field names for the fields.
let fields_names: Vec<_> = fields
.iter()
.enumerate()
.map(|(i, field)| (field, field_i(i)))
.collect();
// Declare each field that will be deserialized.
let let_values = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(field, name)| {
let field_ty = field.ty;
quote! {
let mut #name: _serde::#private::Option<#field_ty> = _serde::#private::None;
}
});
// Collect contents for flatten fields into a buffer
let let_collect = if has_flatten {
Some(quote! {
let mut __collect = _serde::#private::Vec::<_serde::#private::Option<(
_serde::#private::de::Content,
_serde::#private::de::Content
)>>::new();
})
} else {
None
};
// Match arms to extract a value for a field.
let value_arms = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(field, name)| {
let deser_name = field.attrs.name().deserialize_name();
let visit = match field.attrs.deserialize_with() {
None => {
let field_ty = field.ty;
let span = field.original.span();
let func =
quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>);
quote! {
#func(&mut __map)?
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({
#wrapper
match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) {
_serde::#private::Ok(__wrapper) => __wrapper.value,
_serde::#private::Err(__err) => {
return _serde::#private::Err(__err);
}
}
})
}
};
quote! {
__Field::#name => {
if _serde::#private::Option::is_some(&#name) {
return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name));
}
#name = _serde::#private::Some(#visit);
}
}
});
// Visit ignored values to consume them
let ignored_arm = if has_flatten {
Some(quote! {
__Field::__other(__name) => {
__collect.push(_serde::#private::Some((
__name,
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?)));
}
})
} else if cattrs.deny_unknown_fields() {
None
} else {
Some(quote! {
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
})
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
quote! {
// FIXME: Once feature(exhaustive_patterns) is stable:
// let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
_serde::#private::Option::map(
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|__impossible| match __impossible {});
}
} else {
quote! {
while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
#(#value_arms)*
#ignored_arm
}
}
}
};
let extract_values = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(field, name)| {
let missing_expr = Match(expr_is_missing(field, cattrs));
quote! {
let #name = match #name {
_serde::#private::Some(#name) => #name,
_serde::#private::None => #missing_expr
};
}
});
let extract_collected = fields_names
.iter()
.filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing())
.map(|(field, name)| {
let field_ty = field.ty;
let func = match field.attrs.deserialize_with() {
None => {
let span = field.original.span();
quote_spanned!(span=> _serde::de::Deserialize::deserialize)
}
Some(path) => quote!(#path),
};
quote! {
let #name: #field_ty = #func(
_serde::#private::de::FlatMapDeserializer(
&mut __collect,
_serde::#private::PhantomData))?;
}
});
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()
{
if let _serde::#private::Some(__key) = _serde::#private::de::content_as_str(&__key) {
return _serde::#private::Err(
_serde::de::Error::custom(format_args!("unknown field `{}`", &__key)));
} else {
return _serde::#private::Err(
_serde::de::Error::custom(format_args!("unexpected map key")));
}
}
})
} else {
None
};
let result = fields_names.iter().map(|(field, name)| {
let member = &field.member;
if field.attrs.skip_deserializing() {
let value = Expr(expr_is_missing(field, cattrs));
quote!(#member: #value)
} else {
quote!(#member: #name)
}
});
let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!(
let __default: Self::Value = _serde::#private::Default::default();
)),
// If #path returns wrong type, error will be reported here (^^^^^).
// We attach span of the path to the function so it will be reported
// on the #[serde(default = "...")]
// ^^^^^
attr::Default::Path(path) => Some(quote_spanned!(path.span()=>
let __default: Self::Value = #path();
)),
attr::Default::None => {
// We don't need the default value, to prevent an unused variable warning
// we'll leave the line empty.
None
}
};
let mut result = quote!(#struct_path { #(#result),* });
if params.has_getter {
let this_type = &params.this_type;
let (_, ty_generics, _) = params.generics.split_for_impl();
result = quote! {
_serde::#private::Into::<#this_type #ty_generics>::into(#result)
};
}
quote_block! {
#(#let_values)*
#let_collect
#match_keys
#let_default
#(#extract_values)*
#(#extract_collected)*
#collected_deny_unknown_fields
_serde::#private::Ok(#result)
}
}
/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}`
#[cfg(feature = "deserialize_in_place")]
pub(super) fn deserialize_in_place(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> Option<Fragment> {
// for now we do not support in_place deserialization for structs that
// are represented as map.
if has_flatten(fields) {
return None;
}
let this_type = &params.this_type;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let expecting = format!("struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
let deserialized_fields: Vec<_> = fields
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing())
.map(|(i, field)| FieldWithAliases {
ident: field_i(i),
aliases: field.attrs.aliases(),
})
.collect();
let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, false);
let mut_seq = if deserialized_fields.is_empty() {
quote!(_)
} else {
quote!(mut __seq)
};
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs));
let field_names = deserialized_fields.iter().flat_map(|field| field.aliases);
let type_name = cattrs.name().deserialize_name();
let in_place_impl_generics = de_impl_generics.in_place();
let in_place_ty_generics = de_ty_generics.in_place();
let place_life = place_lifetime();
Some(quote_block! {
#field_visitor
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
type Value = ();
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#[inline]
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
#[inline]
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::MapAccess<#delife>,
{
#visit_map
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor {
place: __place,
lifetime: _serde::#private::PhantomData,
})
})
}
#[cfg(feature = "deserialize_in_place")]
fn deserialize_map_in_place(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> Fragment {
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
.iter()
.enumerate()
.map(|(i, field)| (field, field_i(i)))
.collect();
// For deserialize_in_place, declare booleans for each field that will be
// deserialized.
let let_flags = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|(_, name)| {
quote! {
let mut #name: bool = false;
}
});
// Match arms to extract a value for a field.
let value_arms_from = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|(field, name)| {
let deser_name = field.attrs.name().deserialize_name();
let member = &field.member;
let visit = match field.attrs.deserialize_with() {
None => {
quote! {
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::InPlaceSeed(&mut self.place.#member))?
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({
#wrapper
self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) {
_serde::#private::Ok(__wrapper) => __wrapper.value,
_serde::#private::Err(__err) => {
return _serde::#private::Err(__err);
}
};
})
}
};
quote! {
__Field::#name => {
if #name {
return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name));
}
#visit;
#name = true;
}
}
});
// Visit ignored values to consume them
let ignored_arm = if cattrs.deny_unknown_fields() {
None
} else {
Some(quote! {
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
})
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
quote! {
// FIXME: Once feature(exhaustive_patterns) is stable:
// let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
_serde::#private::Option::map(
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|__impossible| match __impossible {});
}
} else {
quote! {
while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
#(#value_arms_from)*
#ignored_arm
}
}
}
};
let check_flags = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|(field, name)| {
let missing_expr = expr_is_missing(field, cattrs);
// If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place.
if field.attrs.default().is_none()
&& cattrs.default().is_none()
&& field.attrs.deserialize_with().is_some()
{
let missing_expr = Stmts(missing_expr);
quote! {
if !#name {
#missing_expr;
}
}
} else {
let member = &field.member;
let missing_expr = Expr(missing_expr);
quote! {
if !#name {
self.place.#member = #missing_expr;
};
}
}
});
let this_type = &params.this_type;
let (_, ty_generics, _) = params.generics.split_for_impl();
let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!(
let __default: #this_type #ty_generics = _serde::#private::Default::default();
)),
// If #path returns wrong type, error will be reported here (^^^^^).
// We attach span of the path to the function so it will be reported
// on the #[serde(default = "...")]
// ^^^^^
attr::Default::Path(path) => Some(quote_spanned!(path.span()=>
let __default: #this_type #ty_generics = #path();
)),
attr::Default::None => {
// We don't need the default value, to prevent an unused variable warning
// we'll leave the line empty.
None
}
};
quote_block! {
#(#let_flags)*
#match_keys
#let_default
#(#check_flags)*
_serde::#private::Ok(())
}
}
/// Generates enum and its `Deserialize` implementation that represents each
/// non-skipped field of the struct
fn deserialize_field_identifier(
deserialized_fields: &[FieldWithAliases],
cattrs: &attr::Container,
has_flatten: bool,
) -> Stmts {
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))
} else if cattrs.deny_unknown_fields() {
(None, None)
} else {
let ignore_variant = quote!(__ignore,);
let fallthrough = quote!(_serde::#private::Ok(__Field::__ignore));
(Some(ignore_variant), Some(fallthrough))
};
Stmts(identifier::deserialize_generated(
deserialized_fields,
has_flatten,
false,
ignore_variant,
fallthrough,
))
}
+283
View File
@@ -0,0 +1,283 @@
use crate::de::{deserialize_seq, has_flatten, Parameters, TupleForm};
#[cfg(feature = "deserialize_in_place")]
use crate::de::{deserialize_seq_in_place, place_lifetime};
use crate::fragment::{Fragment, Stmts};
use crate::internals::ast::Field;
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);`
pub(super) fn deserialize(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
form: TupleForm,
) -> Fragment {
assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly.
let construct = if params.has_getter {
let local = &params.local;
quote!(#local)
} else {
quote!(#this_value)
};
let type_path = match form {
TupleForm::Tuple => construct,
TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => {
quote!(#construct::#variant_ident)
}
};
let expecting = match form {
TupleForm::Tuple => format!("tuple struct {}", params.type_name()),
TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => {
format!("tuple variant {}::{}", params.type_name(), variant_ident)
}
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let nfields = fields.len();
let visit_newtype_struct = match form {
TupleForm::Tuple if nfields == 1 => {
Some(deserialize_newtype_struct(&type_path, params, &fields[0]))
}
_ => None,
};
let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, false, cattrs, expecting,
));
let visitor_expr = quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
}
};
let dispatch = match form {
TupleForm::Tuple if nfields == 1 => {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)
}
}
TupleForm::Tuple => {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)
}
}
TupleForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr)
},
TupleForm::Untagged(_) => quote! {
_serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr)
},
};
let visitor_var = if field_count == 0 {
quote!(_)
} else {
quote!(mut __seq)
};
quote_block! {
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#visit_newtype_struct
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
}
#dispatch
}
}
fn deserialize_newtype_struct(
type_path: &TokenStream,
params: &Parameters,
field: &Field,
) -> TokenStream {
let delife = params.borrowed.de_lifetime();
let field_ty = field.ty;
let deserializer_var = quote!(__e);
let value = match field.attrs.deserialize_with() {
None => {
let span = field.original.span();
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
quote! {
#func(#deserializer_var)?
}
}
Some(path) => {
// If #path returns wrong type, error will be reported here (^^^^^).
// We attach span of the path to the function so it will be reported
// on the #[serde(with = "...")]
// ^^^^^
quote_spanned! {path.span()=>
#path(#deserializer_var)?
}
}
};
let mut result = quote!(#type_path(__field0));
if params.has_getter {
let this_type = &params.this_type;
let (_, ty_generics, _) = params.generics.split_for_impl();
result = quote! {
_serde::#private::Into::<#this_type #ty_generics>::into(#result)
};
}
quote! {
#[inline]
fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result<Self::Value, __E::Error>
where
__E: _serde::Deserializer<#delife>,
{
let __field0: #field_ty = #value;
_serde::#private::Ok(#result)
}
}
}
/// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);`
#[cfg(feature = "deserialize_in_place")]
pub(super) fn deserialize_in_place(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> Fragment {
assert!(
!has_flatten(fields),
"tuples and tuple variants cannot have flatten fields"
);
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let expecting = format!("tuple struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
let nfields = fields.len();
let visit_newtype_struct = if nfields == 1 {
// We do not generate deserialize_in_place if every field has a
// deserialize_with.
assert!(fields[0].attrs.deserialize_with().is_none());
Some(quote! {
#[inline]
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::#private::Result<Self::Value, __E::Error>
where
__E: _serde::Deserializer<#delife>,
{
_serde::Deserialize::deserialize_in_place(__e, &mut self.place.0)
}
})
} else {
None
};
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
let visitor_expr = quote! {
__Visitor {
place: __place,
lifetime: _serde::#private::PhantomData,
}
};
let type_name = cattrs.name().deserialize_name();
let dispatch = if nfields == 1 {
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else {
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
};
let visitor_var = if field_count == 0 {
quote!(_)
} else {
quote!(mut __seq)
};
let in_place_impl_generics = de_impl_generics.in_place();
let in_place_ty_generics = de_ty_generics.in_place();
let place_life = place_lifetime();
quote_block! {
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
type Value = ();
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#visit_newtype_struct
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
}
#dispatch
}
}
+52
View File
@@ -0,0 +1,52 @@
use crate::de::Parameters;
use crate::fragment::Fragment;
use crate::internals::attr;
use crate::private;
use quote::quote;
/// Generates `Deserialize::deserialize` body for a `struct Unit;`
pub(super) fn deserialize(params: &Parameters, cattrs: &attr::Container) -> Fragment {
let this_type = &params.this_type;
let this_value = &params.this_value;
let type_name = cattrs.name().deserialize_name();
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
params.generics_with_de_lifetime();
let delife = params.borrowed.de_lifetime();
let expecting = format!("unit struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
}
#[automatically_derived]
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
_serde::#private::Formatter::write_str(__formatter, #expecting)
}
#[inline]
fn visit_unit<__E>(self) -> _serde::#private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
_serde::#private::Ok(#this_value)
}
}
_serde::Deserializer::deserialize_unit_struct(
__deserializer,
#type_name,
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
},
)
}
}
+56
View File
@@ -0,0 +1,56 @@
use proc_macro2::TokenStream;
use quote::quote;
pub fn allow_deprecated(input: &syn::DeriveInput) -> Option<TokenStream> {
if should_allow_deprecated(input) {
Some(quote! { #[allow(deprecated)] })
} else {
None
}
}
/// Determine if an `#[allow(deprecated)]` should be added to the derived impl.
///
/// This should happen if the derive input or an enum variant it contains has
/// one of:
/// - `#[deprecated]`
/// - `#[allow(deprecated)]`
fn should_allow_deprecated(input: &syn::DeriveInput) -> bool {
if contains_deprecated(&input.attrs) {
return true;
}
if let syn::Data::Enum(data_enum) = &input.data {
for variant in &data_enum.variants {
if contains_deprecated(&variant.attrs) {
return true;
}
}
}
false
}
/// Check whether the given attributes contains one of:
/// - `#[deprecated]`
/// - `#[allow(deprecated)]`
fn contains_deprecated(attrs: &[syn::Attribute]) -> bool {
for attr in attrs {
if attr.path().is_ident("deprecated") {
return true;
}
if let syn::Meta::List(meta_list) = &attr.meta {
if meta_list.path.is_ident("allow") {
let mut allow_deprecated = false;
let _ = meta_list.parse_nested_meta(|meta| {
if meta.path.is_ident("deprecated") {
allow_deprecated = true;
}
Ok(())
});
if allow_deprecated {
return true;
}
}
}
}
false
}
+9 -1
View File
@@ -14,9 +14,17 @@ pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> Token
quote! {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
#[allow(
non_upper_case_globals,
unused_attributes,
unused_qualifications,
clippy::absolute_paths,
)]
const _: () = {
#use_serde
_serde::__require_serde_not_serde_core!();
#code
};
}
+21 -8
View File
@@ -1,6 +1,7 @@
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
use crate::internals::{attr, check, Ctxt, Derive};
use proc_macro2::Ident;
use syn::punctuated::Punctuated;
use syn::Token;
@@ -62,13 +63,17 @@ impl<'a> Container<'a> {
cx: &Ctxt,
item: &'a syn::DeriveInput,
derive: Derive,
private: &Ident,
) -> Option<Container<'a>> {
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())),
syn::Data::Enum(data) => {
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default(), private))
}
syn::Data::Struct(data) => {
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
let (style, fields) =
struct_from_ast(cx, &data.fields, None, attrs.default(), private);
Data::Struct(style, fields)
}
syn::Data::Union(_) => {
@@ -129,13 +134,19 @@ fn enum_from_ast<'a>(
cx: &Ctxt,
variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default,
private: &Ident,
) -> Vec<Variant<'a>> {
let variants: Vec<Variant> = variants
.iter()
.map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) =
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
let (style, fields) = struct_from_ast(
cx,
&variant.fields,
Some(&attrs),
container_default,
private,
);
Variant {
ident: variant.ident.clone(),
attrs,
@@ -165,19 +176,20 @@ fn struct_from_ast<'a>(
fields: &'a syn::Fields,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
private: &Ident,
) -> (Style, Vec<Field<'a>>) {
match fields {
syn::Fields::Named(fields) => (
Style::Struct,
fields_from_ast(cx, &fields.named, attrs, container_default),
fields_from_ast(cx, &fields.named, attrs, container_default, private),
),
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
Style::Newtype,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
fields_from_ast(cx, &fields.unnamed, attrs, container_default, private),
),
syn::Fields::Unnamed(fields) => (
Style::Tuple,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
fields_from_ast(cx, &fields.unnamed, attrs, container_default, private),
),
syn::Fields::Unit => (Style::Unit, Vec::new()),
}
@@ -188,6 +200,7 @@ fn fields_from_ast<'a>(
fields: &'a Punctuated<syn::Field, Token![,]>,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
private: &Ident,
) -> Vec<Field<'a>> {
fields
.iter()
@@ -197,7 +210,7 @@ fn fields_from_ast<'a>(
Some(ident) => syn::Member::Named(ident.clone()),
None => syn::Member::Unnamed(i.into()),
},
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default, private),
ty: &field.ty,
original: field,
})
+74 -127
View File
@@ -1,14 +1,15 @@
use crate::internals::name::{MultiName, Name};
use crate::internals::symbol::*;
use crate::internals::{ungroup, Ctxt};
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use syn::meta::ParseNestedMeta;
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::{parse_quote, token, Ident, Lifetime, Token};
use syn::spanned::Spanned;
use syn::{token, Ident, Lifetime, Token};
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
@@ -20,7 +21,7 @@ use syn::{parse_quote, token, Ident, Lifetime, Token};
pub use crate::internals::case::RenameRule;
struct Attr<'c, T> {
pub(crate) struct Attr<'c, T> {
cx: &'c Ctxt,
name: Symbol,
tokens: TokenStream,
@@ -61,7 +62,7 @@ impl<'c, T> Attr<'c, T> {
}
}
fn get(self) -> Option<T> {
pub(crate) fn get(self) -> Option<T> {
self.value
}
@@ -89,7 +90,7 @@ impl<'c> BoolAttr<'c> {
}
}
struct VecAttr<'c, T> {
pub(crate) struct VecAttr<'c, T> {
cx: &'c Ctxt,
name: Symbol,
first_dup_tokens: TokenStream,
@@ -124,63 +125,13 @@ impl<'c, T> VecAttr<'c, T> {
}
}
fn get(self) -> Vec<T> {
pub(crate) fn get(self) -> Vec<T> {
self.values
}
}
pub struct Name {
serialize: String,
serialize_renamed: bool,
deserialize: String,
deserialize_renamed: bool,
deserialize_aliases: BTreeSet<String>,
}
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
impl Name {
fn from_attrs(
source_name: String,
ser_name: Attr<String>,
de_name: Attr<String>,
de_aliases: Option<VecAttr<String>>,
) -> Name {
let mut alias_set = BTreeSet::new();
if let Some(de_aliases) = de_aliases {
for alias_name in de_aliases.get() {
alias_set.insert(alias_name);
}
}
let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some();
let de_name = de_name.get();
let de_renamed = de_name.is_some();
Name {
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
serialize_renamed: ser_renamed,
deserialize: de_name.unwrap_or(source_name),
deserialize_renamed: de_renamed,
deserialize_aliases: alias_set,
}
}
/// Return the container name for the container when serializing.
pub fn serialize_name(&self) -> &str {
&self.serialize
}
/// Return the container name for the container when deserializing.
pub fn deserialize_name(&self) -> &str {
&self.deserialize
}
fn deserialize_aliases(&self) -> &BTreeSet<String> {
&self.deserialize_aliases
}
fn unraw(ident: &Ident) -> Ident {
Ident::new(ident.to_string().trim_start_matches("r#"), ident.span())
}
#[derive(Copy, Clone)]
@@ -202,7 +153,7 @@ impl RenameAllRules {
/// Represents struct or enum attribute information.
pub struct Container {
name: Name,
name: MultiName,
transparent: bool,
deny_unknown_fields: bool,
default: Default,
@@ -326,8 +277,8 @@ impl Container {
// #[serde(rename = "foo")]
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
let (ser, de) = get_renames(cx, RENAME, &meta)?;
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value));
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
de_name.set_opt(&meta.path, de.as_ref().map(Name::from));
} else if meta.path == RENAME_ALL {
// #[serde(rename_all = "foo")]
// #[serde(rename_all(serialize = "foo", deserialize = "bar"))]
@@ -566,7 +517,7 @@ impl Container {
}
Container {
name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None),
name: MultiName::from_attrs(Name::from(&unraw(&item.ident)), ser_name, de_name, None),
transparent: transparent.get(),
deny_unknown_fields: deny_unknown_fields.get(),
default: default.get().unwrap_or(Default::None),
@@ -593,7 +544,7 @@ impl Container {
}
}
pub fn name(&self) -> &Name {
pub fn name(&self) -> &MultiName {
&self.name
}
@@ -657,11 +608,6 @@ impl Container {
self.serde_path.as_ref()
}
pub fn serde_path(&self) -> Cow<syn::Path> {
self.custom_serde_path()
.map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed)
}
/// Error message generated when type can't be deserialized.
/// If `None`, default message will be used
pub fn expecting(&self) -> Option<&str> {
@@ -780,7 +726,7 @@ fn decide_identifier(
/// Represents variant attribute information
pub struct Variant {
name: Name,
name: MultiName,
rename_all_rules: RenameAllRules,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
@@ -831,15 +777,15 @@ impl Variant {
// #[serde(rename = "foo")]
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
let (ser, de) = get_multiple_renames(cx, &meta)?;
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
for de_value in de {
de_name.set_if_none(de_value.value());
de_aliases.insert(&meta.path, de_value.value());
de_name.set_if_none(Name::from(&de_value));
de_aliases.insert(&meta.path, Name::from(&de_value));
}
} else if meta.path == ALIAS {
// #[serde(alias = "foo")]
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
de_aliases.insert(&meta.path, s.value());
de_aliases.insert(&meta.path, Name::from(&s));
}
} else if meta.path == RENAME_ALL {
// #[serde(rename_all = "foo")]
@@ -888,13 +834,13 @@ impl Variant {
ser_path
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
.push(Ident::new("serialize", ser_path.span()).into());
serialize_with.set(&meta.path, ser_path);
let mut de_path = path;
de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
.push(Ident::new("deserialize", de_path.span()).into());
deserialize_with.set(&meta.path, de_path);
}
} else if meta.path == SERIALIZE_WITH {
@@ -946,7 +892,12 @@ impl Variant {
}
Variant {
name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)),
name: MultiName::from_attrs(
Name::from(&unraw(&variant.ident)),
ser_name,
de_name,
Some(de_aliases),
),
rename_all_rules: RenameAllRules {
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
@@ -963,20 +914,23 @@ impl Variant {
}
}
pub fn name(&self) -> &Name {
pub fn name(&self) -> &MultiName {
&self.name
}
pub fn aliases(&self) -> &BTreeSet<String> {
pub fn aliases(&self) -> &BTreeSet<Name> {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
self.name.serialize.value =
rules.serialize.apply_to_variant(&self.name.serialize.value);
}
if !self.name.deserialize_renamed {
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
self.name.deserialize.value = rules
.deserialize
.apply_to_variant(&self.name.deserialize.value);
}
self.name
.deserialize_aliases
@@ -1022,7 +976,7 @@ impl Variant {
/// Represents field attribute information
pub struct Field {
name: Name,
name: MultiName,
skip_serializing: bool,
skip_deserializing: bool,
skip_serializing_if: Option<syn::ExprPath>,
@@ -1064,6 +1018,7 @@ impl Field {
field: &syn::Field,
attrs: Option<&Variant>,
container_default: &Default,
private: &Ident,
) -> Self {
let mut ser_name = Attr::none(cx, RENAME);
let mut de_name = Attr::none(cx, RENAME);
@@ -1081,8 +1036,11 @@ impl Field {
let mut flatten = BoolAttr::none(cx, FLATTEN);
let ident = match &field.ident {
Some(ident) => unraw(ident),
None => index.to_string(),
Some(ident) => Name::from(&unraw(ident)),
None => Name {
value: index.to_string(),
span: Span::call_site(),
},
};
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
@@ -1118,15 +1076,15 @@ impl Field {
// #[serde(rename = "foo")]
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
let (ser, de) = get_multiple_renames(cx, &meta)?;
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
for de_value in de {
de_name.set_if_none(de_value.value());
de_aliases.insert(&meta.path, de_value.value());
de_name.set_if_none(Name::from(&de_value));
de_aliases.insert(&meta.path, Name::from(&de_value));
}
} else if meta.path == ALIAS {
// #[serde(alias = "foo")]
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
de_aliases.insert(&meta.path, s.value());
de_aliases.insert(&meta.path, Name::from(&s));
}
} else if meta.path == DEFAULT {
if meta.input.peek(Token![=]) {
@@ -1170,13 +1128,13 @@ impl Field {
ser_path
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
.push(Ident::new("serialize", ser_path.span()).into());
serialize_with.set(&meta.path, ser_path);
let mut de_path = path;
de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
.push(Ident::new("deserialize", de_path.span()).into());
deserialize_with.set(&meta.path, de_path);
}
} else if meta.path == BOUND {
@@ -1227,13 +1185,11 @@ impl Field {
}
}
// Is skip_deserializing, initialize the field to Default::default() unless a
// If skip_deserializing, initialize the field to Default::default() unless a
// different default is specified by `#[serde(default = "...")]` on
// ourselves or our container (e.g. the struct we are in).
if let Default::None = *container_default {
if skip_deserializing.0.value.is_some() {
default.set_if_none(Default::Default);
}
if container_default.is_none() && skip_deserializing.0.value.is_some() {
default.set_if_none(Default::Default);
}
let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default();
@@ -1254,7 +1210,7 @@ impl Field {
};
let span = Span::call_site();
path.segments.push(Ident::new("_serde", span).into());
path.segments.push(Ident::new("__private", span).into());
path.segments.push(private.clone().into());
path.segments.push(Ident::new("de", span).into());
path.segments
.push(Ident::new("borrow_cow_str", span).into());
@@ -1271,7 +1227,7 @@ impl Field {
};
let span = Span::call_site();
path.segments.push(Ident::new("_serde", span).into());
path.segments.push(Ident::new("__private", span).into());
path.segments.push(private.clone().into());
path.segments.push(Ident::new("de", span).into());
path.segments
.push(Ident::new("borrow_cow_bytes", span).into());
@@ -1289,7 +1245,7 @@ impl Field {
}
Field {
name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
name: MultiName::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
skip_serializing: skip_serializing.get(),
skip_deserializing: skip_deserializing.get(),
skip_serializing_if: skip_serializing_if.get(),
@@ -1305,20 +1261,22 @@ impl Field {
}
}
pub fn name(&self) -> &Name {
pub fn name(&self) -> &MultiName {
&self.name
}
pub fn aliases(&self) -> &BTreeSet<String> {
pub fn aliases(&self) -> &BTreeSet<Name> {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value);
}
if !self.name.deserialize_renamed {
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
self.name.deserialize.value = rules
.deserialize
.apply_to_field(&self.name.deserialize.value);
}
self.name
.deserialize_aliases
@@ -1499,9 +1457,8 @@ fn parse_lit_into_path(
attr_name: Symbol,
meta: &ParseNestedMeta,
) -> syn::Result<Option<syn::Path>> {
let string = match get_lit_str(cx, attr_name, meta)? {
Some(string) => string,
None => return Ok(None),
let Some(string) = get_lit_str(cx, attr_name, meta)? else {
return Ok(None);
};
Ok(match string.parse() {
@@ -1521,9 +1478,8 @@ fn parse_lit_into_expr_path(
attr_name: Symbol,
meta: &ParseNestedMeta,
) -> syn::Result<Option<syn::ExprPath>> {
let string = match get_lit_str(cx, attr_name, meta)? {
Some(string) => string,
None => return Ok(None),
let Some(string) = get_lit_str(cx, attr_name, meta)? else {
return Ok(None);
};
Ok(match string.parse() {
@@ -1544,9 +1500,8 @@ fn parse_lit_into_where(
meta_item_name: Symbol,
meta: &ParseNestedMeta,
) -> syn::Result<Vec<syn::WherePredicate>> {
let string = match get_lit_str2(cx, attr_name, meta_item_name, meta)? {
Some(string) => string,
None => return Ok(Vec::new()),
let Some(string) = get_lit_str2(cx, attr_name, meta_item_name, meta)? else {
return Ok(Vec::new());
};
Ok(
@@ -1565,9 +1520,8 @@ fn parse_lit_into_ty(
attr_name: Symbol,
meta: &ParseNestedMeta,
) -> syn::Result<Option<syn::Type>> {
let string = match get_lit_str(cx, attr_name, meta)? {
Some(string) => string,
None => return Ok(None),
let Some(string) = get_lit_str(cx, attr_name, meta)? else {
return Ok(None);
};
Ok(match string.parse() {
@@ -1588,9 +1542,8 @@ fn parse_lit_into_lifetimes(
cx: &Ctxt,
meta: &ParseNestedMeta,
) -> syn::Result<BTreeSet<syn::Lifetime>> {
let string = match get_lit_str(cx, BORROW, meta)? {
Some(string) => string,
None => return Ok(BTreeSet::new()),
let Some(string) = get_lit_str(cx, BORROW, meta)? else {
return Ok(BTreeSet::new());
};
if let Ok(lifetimes) = string.parse_with(|input: ParseStream| {
@@ -1660,11 +1613,8 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
return false;
}
};
let seg = match path.segments.last() {
Some(seg) => seg,
None => {
return false;
}
let Some(seg) = path.segments.last() else {
return false;
};
let args = match &seg.arguments {
syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args,
@@ -1687,11 +1637,8 @@ fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
return false;
}
};
let seg = match path.segments.last() {
Some(seg) => seg,
None => {
return false;
}
let Some(seg) = path.segments.last() else {
return false;
};
let args = match &seg.arguments {
syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args,
@@ -1768,7 +1715,7 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
// attribute on the field so there must be at least one borrowable lifetime.
fn borrowable_lifetimes(
cx: &Ctxt,
name: &str,
name: &Name,
field: &syn::Field,
) -> Result<BTreeSet<syn::Lifetime>, ()> {
let mut lifetimes = BTreeSet::new();
+2 -2
View File
@@ -329,13 +329,13 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
let name = field.attrs.name();
let ser_name = name.serialize_name();
if check_ser && ser_name == tag {
if check_ser && ser_name.value == tag {
diagnose_conflict();
return;
}
for de_name in field.attrs.aliases() {
if check_de && de_name == tag {
if check_de && de_name.value == tag {
diagnose_conflict();
return;
}
+2 -3
View File
@@ -46,9 +46,8 @@ impl Ctxt {
pub fn check(self) -> syn::Result<()> {
let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
let mut combined = match errors.next() {
Some(first) => first,
None => return Ok(()),
let Some(mut combined) = errors.next() else {
return Ok(());
};
for rest in errors {
+1
View File
@@ -1,5 +1,6 @@
pub mod ast;
pub mod attr;
pub mod name;
mod case;
mod check;
+113
View File
@@ -0,0 +1,113 @@
use crate::internals::attr::{Attr, VecAttr};
use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::{self, Display};
use syn::LitStr;
pub struct MultiName {
pub(crate) serialize: Name,
pub(crate) serialize_renamed: bool,
pub(crate) deserialize: Name,
pub(crate) deserialize_renamed: bool,
pub(crate) deserialize_aliases: BTreeSet<Name>,
}
impl MultiName {
pub(crate) fn from_attrs(
source_name: Name,
ser_name: Attr<Name>,
de_name: Attr<Name>,
de_aliases: Option<VecAttr<Name>>,
) -> Self {
let mut alias_set = BTreeSet::new();
if let Some(de_aliases) = de_aliases {
for alias_name in de_aliases.get() {
alias_set.insert(alias_name);
}
}
let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some();
let de_name = de_name.get();
let de_renamed = de_name.is_some();
MultiName {
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
serialize_renamed: ser_renamed,
deserialize: de_name.unwrap_or(source_name),
deserialize_renamed: de_renamed,
deserialize_aliases: alias_set,
}
}
/// Return the container name for the container when serializing.
pub fn serialize_name(&self) -> &Name {
&self.serialize
}
/// Return the container name for the container when deserializing.
pub fn deserialize_name(&self) -> &Name {
&self.deserialize
}
pub(crate) fn deserialize_aliases(&self) -> &BTreeSet<Name> {
&self.deserialize_aliases
}
}
#[derive(Clone)]
pub struct Name {
pub value: String,
pub span: Span,
}
impl ToTokens for Name {
fn to_tokens(&self, tokens: &mut TokenStream) {
LitStr::new(&self.value, self.span).to_tokens(tokens);
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&self.value, &other.value)
}
}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}
impl Eq for Name {}
impl PartialEq for Name {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl From<&Ident> for Name {
fn from(ident: &Ident) -> Self {
Name {
value: ident.to_string(),
span: ident.span(),
}
}
}
impl From<&LitStr> for Name {
fn from(lit: &LitStr) -> Self {
Name {
value: lit.value(),
span: lit.span(),
}
}
}
impl Display for Name {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.value, formatter)
}
}
+4 -3
View File
@@ -2,7 +2,6 @@ use crate::internals::respan::respan;
use proc_macro2::Span;
use quote::ToTokens;
use std::mem;
use syn::punctuated::Punctuated;
use syn::{
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate,
@@ -49,7 +48,7 @@ impl ReplaceReceiver<'_> {
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
let segments = mem::replace(&mut path.segments, Punctuated::new());
let segments = mem::take(&mut path.segments);
path.segments = segments.into_pairs().skip(1).collect();
}
@@ -209,7 +208,9 @@ impl ReplaceReceiver<'_> {
match bound {
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
TypeParamBound::Lifetime(_)
| TypeParamBound::PreciseCapture(_)
| TypeParamBound::Verbatim(_) => {}
_ => {}
}
}
+2 -2
View File
@@ -46,7 +46,7 @@ impl PartialEq<Symbol> for Ident {
}
}
impl<'a> PartialEq<Symbol> for &'a Ident {
impl PartialEq<Symbol> for &Ident {
fn eq(&self, word: &Symbol) -> bool {
*self == word.0
}
@@ -58,7 +58,7 @@ impl PartialEq<Symbol> for Path {
}
}
impl<'a> PartialEq<Symbol> for &'a Path {
impl PartialEq<Symbol> for &Path {
fn eq(&self, word: &Symbol) -> bool {
self.is_ident(word.0)
}
+26 -1
View File
@@ -13,7 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.209")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.228")]
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
// Ignored clippy lints
#![allow(
@@ -27,6 +27,7 @@
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
clippy::manual_map,
clippy::match_like_matches_macro,
clippy::needless_lifetimes,
clippy::needless_pass_by_value,
clippy::too_many_arguments,
clippy::trivially_copy_pass_by_ref,
@@ -40,6 +41,7 @@
clippy::cast_possible_truncation,
clippy::checked_conversions,
clippy::doc_markdown,
clippy::elidable_lifetime_names,
clippy::enum_glob_use,
clippy::indexing_slicing,
clippy::items_after_statements,
@@ -55,12 +57,14 @@
clippy::single_match_else,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::uninlined_format_args,
clippy::unseparated_literal_suffix,
clippy::unused_self,
clippy::use_self,
clippy::wildcard_imports
)]
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
extern crate proc_macro2;
extern crate quote;
@@ -71,6 +75,8 @@ extern crate proc_macro;
mod internals;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::{ToTokens, TokenStreamExt as _};
use syn::parse_macro_input;
use syn::DeriveInput;
@@ -80,11 +86,30 @@ mod bound;
mod fragment;
mod de;
mod deprecated;
mod dummy;
mod pretend;
mod ser;
mod this;
#[allow(non_camel_case_types)]
struct private;
impl private {
fn ident(&self) -> Ident {
Ident::new(
concat!("__private", env!("CARGO_PKG_VERSION_PATCH")),
Span::call_site(),
)
}
}
impl ToTokens for private {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.append(self.ident());
}
}
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
+12 -9
View File
@@ -1,4 +1,5 @@
use crate::internals::ast::{Container, Data, Field, Style, Variant};
use crate::private;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
@@ -83,8 +84,8 @@ fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
match _serde::#private::None::<&#type_ident #ty_generics> {
_serde::#private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
}
}
@@ -96,11 +97,12 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
let private2 = private;
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
match _serde::#private::None::<&#type_ident #ty_generics> {
_serde::#private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
let _ = _serde::#private2::ptr::addr_of!(__v.#members);
)*
}
_ => {}
@@ -125,10 +127,11 @@ fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStre
})
.collect::<Vec<_>>();
let private2 = private;
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
match _serde::#private::None::<&#type_ident #ty_generics> {
#(
_serde::__private::Some(#patterns) => {}
_serde::#private2::Some(#patterns) => {}
)*
_ => {}
}
@@ -172,8 +175,8 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
};
quote! {
match _serde::__private::None {
_serde::__private::Some((#(#placeholders,)*)) => {
match _serde::#private::None {
_serde::#private::Some((#(#placeholders,)*)) => {
let _ = #type_ident::#variant_ident #turbofish #pat;
}
_ => {}
+60 -42
View File
@@ -1,7 +1,9 @@
use crate::deprecated::allow_deprecated;
use crate::fragment::{Fragment, Match, Stmts};
use crate::internals::ast::{Container, Data, Field, Style, Variant};
use crate::internals::name::Name;
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
use crate::{bound, dummy, pretend, this};
use crate::{bound, dummy, pretend, private, this};
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
@@ -11,9 +13,8 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
replace_receiver(input);
let ctxt = Ctxt::new();
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
Some(cont) => cont,
None => return Err(ctxt.check().unwrap_err()),
let Some(cont) = Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident()) else {
return Err(ctxt.check().unwrap_err());
};
precondition(&ctxt, &cont);
ctxt.check()?;
@@ -22,16 +23,18 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
let params = Parameters::new(&cont);
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
let body = Stmts(serialize_body(&cont, &params));
let serde = cont.attrs.serde_path();
let allow_deprecated = allow_deprecated(input);
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
#[automatically_derived]
#allow_deprecated
impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
where
__S: #serde::Serializer,
__S: _serde::Serializer,
{
#used
#body
@@ -41,10 +44,11 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
} else {
quote! {
#[automatically_derived]
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
#allow_deprecated
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
where
__S: #serde::Serializer,
__S: _serde::Serializer,
{
#body
}
@@ -148,7 +152,7 @@ fn build_generics(cont: &Container) -> syn::Generics {
}
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
// belong to a variant with a 'skip_serializing` or `serialize_with` attribute,
// belong to a variant with a `skip_serializing` or `serialize_with` attribute,
// are not serialized by us so we do not generate a bound. Fields with a `bound`
// attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Serialize` bound where T is the type of the field.
@@ -210,7 +214,7 @@ fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
let self_var = &params.self_var;
quote_block! {
_serde::Serialize::serialize(
&_serde::__private::Into::<#type_into>::into(_serde::__private::Clone::clone(#self_var)),
&_serde::#private::Into::<#type_into>::into(_serde::#private::Clone::clone(#self_var)),
__serializer)
}
}
@@ -380,7 +384,7 @@ fn serialize_struct_as_map(
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
quote_block! {
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::__private::None)?;
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::#private::None)?;
#tag_field
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
@@ -402,7 +406,7 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
if cattrs.remote().is_some() && cattrs.non_exhaustive() {
arms.push(quote! {
ref unrecognized => _serde::__private::Err(_serde::ser::Error::custom(_serde::__private::ser::CannotSerializeVariant(unrecognized))),
ref unrecognized => _serde::#private::Err(_serde::ser::Error::custom(_serde::#private::ser::CannotSerializeVariant(unrecognized))),
});
}
@@ -429,7 +433,7 @@ fn serialize_variant(
variant_ident
);
let skipped_err = quote! {
_serde::__private::Err(_serde::ser::Error::custom(#skipped_msg))
_serde::#private::Err(_serde::ser::Error::custom(#skipped_msg))
};
let fields_pat = match variant.style {
Style::Unit => quote!(),
@@ -583,7 +587,7 @@ fn serialize_internally_tagged_variant(
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, variant);
return quote_expr! {
_serde::__private::ser::serialize_tagged_newtype(
_serde::#private::ser::serialize_tagged_newtype(
__serializer,
#enum_ident_str,
#variant_ident_str,
@@ -612,7 +616,7 @@ fn serialize_internally_tagged_variant(
}
let span = field.original.span();
let func = quote_spanned!(span=> _serde::__private::ser::serialize_tagged_newtype);
let func = quote_spanned!(span=> _serde::#private::ser::serialize_tagged_newtype);
quote_expr! {
#func(
__serializer,
@@ -646,7 +650,7 @@ fn serialize_adjacently_tagged_variant(
let type_name = cattrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
let serialize_variant = quote! {
&_serde::__private::ser::AdjacentlyTaggedEnumVariant {
&_serde::#private::ser::AdjacentlyTaggedEnumVariant {
enum_name: #type_name,
variant_index: #variant_index,
variant_name: #variant_name,
@@ -729,11 +733,12 @@ fn serialize_adjacently_tagged_variant(
#[doc(hidden)]
struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
}
#[automatically_derived]
impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
@@ -751,7 +756,7 @@ fn serialize_adjacently_tagged_variant(
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #content, &__AdjacentlyTagged {
data: (#(#fields_ident,)*),
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
})?;
_serde::ser::SerializeStruct::end(__struct)
}
@@ -798,9 +803,9 @@ fn serialize_untagged_variant(
enum TupleVariant<'a> {
ExternallyTagged {
type_name: &'a str,
type_name: &'a Name,
variant_index: u32,
variant_name: &'a str,
variant_name: &'a Name,
},
Untagged,
}
@@ -867,11 +872,11 @@ fn serialize_tuple_variant(
enum StructVariant<'a> {
ExternallyTagged {
variant_index: u32,
variant_name: &'a str,
variant_name: &'a Name,
},
InternallyTagged {
tag: &'a str,
variant_name: &'a str,
variant_name: &'a Name,
},
Untagged,
}
@@ -880,7 +885,7 @@ fn serialize_struct_variant(
context: StructVariant,
params: &Parameters,
fields: &[Field],
name: &str,
name: &Name,
) -> Fragment {
if fields.iter().any(|field| field.attrs.flatten()) {
return serialize_struct_variant_with_flatten(context, params, fields, name);
@@ -964,7 +969,7 @@ fn serialize_struct_variant_with_flatten(
context: StructVariant,
params: &Parameters,
fields: &[Field],
name: &str,
name: &Name,
) -> Fragment {
let struct_trait = StructTrait::SerializeMap;
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
@@ -993,18 +998,19 @@ fn serialize_struct_variant_with_flatten(
#[doc(hidden)]
struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
}
#[automatically_derived]
impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
let (#(#members,)*) = self.data;
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None)?;
_serde::#private::None)?;
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
@@ -1017,7 +1023,7 @@ fn serialize_struct_variant_with_flatten(
#variant_name,
&__EnumFlatten {
data: (#(#members,)*),
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
})
}
}
@@ -1025,7 +1031,7 @@ fn serialize_struct_variant_with_flatten(
quote_block! {
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None)?;
_serde::#private::None)?;
_serde::ser::SerializeMap::serialize_entry(
&mut __serde_state,
#tag,
@@ -1039,7 +1045,7 @@ fn serialize_struct_variant_with_flatten(
quote_block! {
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None)?;
_serde::#private::None)?;
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
@@ -1128,7 +1134,7 @@ fn serialize_struct_visitor(
let ser = if field.attrs.flatten() {
let func = quote_spanned!(span=> _serde::Serialize::serialize);
quote! {
#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))?;
#func(&#field_expr, _serde::#private::ser::FlatMapSerializer(&mut __serde_state))?;
}
} else {
let func = struct_trait.serialize_field(span);
@@ -1220,25 +1226,37 @@ fn wrap_serialize_with(
})
});
quote!({
let self_var = quote!(self);
let serializer_var = quote!(__s);
// If #serialize_with returns wrong type, error will be reported on here.
// We attach span of the path to this piece so error will be reported
// on the #[serde(with = "...")]
// ^^^^^
let wrapper_serialize = quote_spanned! {serialize_with.span()=>
#serialize_with(#(#self_var.values.#field_access, )* #serializer_var)
};
quote!(&{
#[doc(hidden)]
struct __SerializeWith #wrapper_impl_generics #where_clause {
values: (#(&'__a #field_tys, )*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
}
#[automatically_derived]
impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause {
fn serialize<__S>(&self, __s: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
fn serialize<__S>(&#self_var, #serializer_var: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
#serialize_with(#(self.values.#field_access, )* __s)
#wrapper_serialize
}
}
&__SerializeWith {
__SerializeWith {
values: (#(#field_exprs, )*),
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
}
})
}
@@ -1274,11 +1292,11 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea
quote!(&#self_var.#member)
};
let ty = field.ty;
quote!(_serde::__private::ser::constrain::<#ty>(#inner))
quote!(_serde::#private::ser::constrain::<#ty>(#inner))
}
(true, Some(getter)) => {
let ty = field.ty;
quote!(_serde::__private::ser::constrain::<#ty>(&#getter(#self_var)))
quote!(_serde::#private::ser::constrain::<#ty>(&#getter(#self_var)))
}
(false, Some(_)) => {
unreachable!("getter is only allowed for remote impls");
+10 -3
View File
@@ -4,13 +4,13 @@ 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"
edition = "2015"
edition = "2021"
exclude = ["build.rs"]
homepage = "https://serde.rs"
keywords = ["serde", "serialization"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.56"
rust-version = "1.68"
[lib]
path = "lib.rs"
@@ -22,4 +22,11 @@ syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "print
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
rustdoc-args = [
"--generate-link-to-definition",
"--generate-macro-expansion",
"--extern-html-root-url=core=https://doc.rust-lang.org",
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
"--extern-html-root-url=std=https://doc.rust-lang.org",
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
]
+4
View File
@@ -9,6 +9,7 @@
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
clippy::manual_map,
clippy::missing_panics_doc,
clippy::needless_lifetimes,
clippy::redundant_field_names,
clippy::result_unit_err,
clippy::should_implement_trait,
@@ -20,6 +21,7 @@
// Ignored clippy_pedantic lints
#![allow(
clippy::doc_markdown,
clippy::elidable_lifetime_names,
clippy::enum_glob_use,
clippy::items_after_statements,
clippy::let_underscore_untyped,
@@ -35,9 +37,11 @@
clippy::single_match_else,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::uninlined_format_args,
clippy::unused_self,
clippy::wildcard_imports
)]
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
extern crate proc_macro2;
extern crate quote;
+3 -3
View File
@@ -2,7 +2,7 @@
name = "serde_test_suite"
version = "0.0.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
edition = "2018"
edition = "2021"
publish = false
[features]
@@ -13,9 +13,9 @@ serde = { path = "../serde" }
[dev-dependencies]
automod = "1.0.1"
fnv = "1.0"
foldhash = "0.2"
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.97", features = ["diff"] }
trybuild = { version = "1.0.108", features = ["diff"] }
+2
View File
@@ -0,0 +1,2 @@
/target/
/Cargo.lock
+7 -1
View File
@@ -2,7 +2,7 @@
name = "serde_derive_tests_no_std"
version = "0.0.0"
authors = ["David Tolnay <dtolnay@gmail.com>"]
edition = "2018"
edition = "2021"
publish = false
[dependencies]
@@ -10,4 +10,10 @@ libc = { version = "0.2", default-features = false }
serde = { path = "../../serde", default-features = false }
serde_derive = { path = "../../serde_derive" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[workspace]
+5 -8
View File
@@ -1,16 +1,13 @@
#![allow(internal_features)]
#![feature(lang_items, start)]
#![no_std]
#![no_main]
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
use core::ffi::c_int;
#[no_mangle]
extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int {
0
}
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe {
+4 -6
View File
@@ -34,9 +34,8 @@ macro_rules! hashset {
$(set.insert($value);)+
set
}};
($hasher:ident @ $($value:expr),+) => {{
use std::hash::BuildHasherDefault;
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
($hasher:ty; $($value:expr),+) => {{
let mut set = HashSet::<_, $hasher>::default();
$(set.insert($value);)+
set
}};
@@ -51,9 +50,8 @@ macro_rules! hashmap {
$(map.insert($key, $value);)+
map
}};
($hasher:ident @ $($key:expr => $value:expr),+) => {{
use std::hash::BuildHasherDefault;
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
($hasher:ty; $($key:expr => $value:expr),+) => {{
let mut map = HashMap::<_, _, $hasher>::default();
$(map.insert($key, $value);)+
map
}};
+2
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde_derive::Deserialize;
#[derive(Deserialize)]
+2
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use serde_derive::Deserialize;
macro_rules! bug {
+1
View File
@@ -2,4 +2,5 @@ use serde_derive::Serialize;
#[derive(Serialize)]
#[serde()]
#[allow(dead_code)]
pub struct S;
+12 -5
View File
@@ -1,4 +1,4 @@
use serde_derive::{Serialize, Deserialize};
use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_tokens, Token};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@@ -18,11 +18,15 @@ fn simple_variant() {
assert_tokens(
&Enum::Simple { a: 42 },
&[
Token::StructVariant { name: "Enum", variant: "Simple", len: 1 },
Token::StructVariant {
name: "Enum",
variant: "Simple",
len: 1,
},
Token::Str("a"),
Token::I32(42),
Token::StructVariantEnd,
]
],
);
}
@@ -31,11 +35,14 @@ fn flatten_variant() {
assert_tokens(
&Enum::Flatten { flatten: (), a: 42 },
&[
Token::NewtypeVariant { name: "Enum", variant: "Flatten" },
Token::NewtypeVariant {
name: "Enum",
variant: "Flatten",
},
Token::Map { len: None },
Token::Str("a"),
Token::I32(42),
Token::MapEnd,
]
],
);
}
+33
View File
@@ -0,0 +1,33 @@
#![allow(clippy::trivially_copy_pass_by_ref, dead_code)]
use serde_derive::{Deserialize, Serialize};
macro_rules! declare_in_macro {
($with:literal) => {
#[derive(Serialize, Deserialize)]
pub struct S {
#[serde(with = $with)]
f: i32,
}
};
}
declare_in_macro!("with");
mod with {
use serde::{Deserializer, Serializer};
pub fn serialize<S>(_: &i32, _: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
unimplemented!()
}
pub fn deserialize<'de, D>(_: D) -> Result<i32, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
+27
View File
@@ -0,0 +1,27 @@
#![allow(clippy::trivially_copy_pass_by_ref, dead_code)]
use serde_derive::Deserialize;
macro_rules! declare_in_macro {
($with:literal) => {
#[derive(Deserialize)]
pub struct S(
#[serde(with = $with)]
#[allow(dead_code)]
i32,
);
};
}
declare_in_macro!("with");
mod with {
use serde::Deserializer;
pub fn deserialize<'de, D>(_: D) -> Result<i32, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
+657 -58
View File
@@ -782,7 +782,7 @@ fn test_unknown_field_rename_enum() {
variant: "SailorMoon",
len: 3,
}],
"unknown variant `SailorMoon`, expected `sailor_moon`",
"unknown variant `SailorMoon`, expected `sailor_moon` or `usagi_tsukino`",
);
assert_de_tokens_error::<AliasEnum>(
@@ -2655,30 +2655,84 @@ mod flatten {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Enum {
Unit,
Newtype(HashMap<String, String>),
Tuple(u32, u32),
Struct { index: u32, value: u32 },
}
#[test]
fn newtype() {
fn unit() {
let value = Flatten {
data: Enum::Unit,
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
};
assert_tokens(
&Flatten {
data: Enum::Newtype(HashMap::from_iter([("key".into(), "value".into())])),
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
},
&value,
&[
Token::Map { len: None },
// data
Token::Str("Unit"), // variant
Token::Unit,
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
// data
Token::Str("Unit"), // variant
Token::Unit,
Token::MapEnd,
],
);
}
#[test]
fn newtype() {
let value = Flatten {
data: Enum::Newtype(HashMap::from_iter([("key".into(), "value".into())])),
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
};
assert_tokens(
&value,
&[
Token::Map { len: None },
// data
Token::Str("Newtype"), // variant
Token::Map { len: Some(1) },
Token::Str("key"),
Token::Str("value"),
Token::MapEnd,
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
// data
Token::Str("Newtype"), // variant
Token::Map { len: Some(1) },
Token::Str("key"),
Token::Str("value"),
Token::MapEnd,
Token::MapEnd,
],
);
}
// Reaches crate::private::de::content::VariantDeserializer::tuple_variant
@@ -2686,23 +2740,42 @@ mod flatten {
// via FlatMapDeserializer::deserialize_enum
#[test]
fn tuple() {
let value = Flatten {
data: Enum::Tuple(0, 42),
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
};
assert_tokens(
&Flatten {
data: Enum::Tuple(0, 42),
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
},
&value,
&[
Token::Map { len: None },
// data
Token::Str("Tuple"), // variant
Token::Seq { len: Some(2) },
Token::U32(0),
Token::U32(42),
Token::SeqEnd,
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
// data
Token::Str("Tuple"), // variant
Token::Seq { len: Some(2) },
Token::U32(0),
Token::U32(42),
Token::SeqEnd,
Token::MapEnd,
],
);
}
// Reaches crate::private::de::content::VariantDeserializer::struct_variant
@@ -2710,26 +2783,45 @@ mod flatten {
// via FlatMapDeserializer::deserialize_enum
#[test]
fn struct_from_seq() {
assert_de_tokens(
&Flatten {
data: Enum::Struct {
index: 0,
value: 42,
},
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
let value = Flatten {
data: Enum::Struct {
index: 0,
value: 42,
},
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
};
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// data
Token::Str("Struct"), // variant
Token::Seq { len: Some(2) },
Token::U32(0), // index
Token::U32(42), // value
Token::SeqEnd,
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
// data
Token::Str("Struct"), // variant
Token::Seq { len: Some(2) },
Token::U32(0), // index
Token::U32(42), // value
Token::SeqEnd,
Token::MapEnd,
],
);
}
// Reaches crate::private::de::content::VariantDeserializer::struct_variant
@@ -2737,16 +2829,18 @@ mod flatten {
// via FlatMapDeserializer::deserialize_enum
#[test]
fn struct_from_map() {
assert_tokens(
&Flatten {
data: Enum::Struct {
index: 0,
value: 42,
},
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
let value = Flatten {
data: Enum::Struct {
index: 0,
value: 42,
},
extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]),
};
assert_tokens(
&value,
&[
Token::Map { len: None },
// data
Token::Str("Struct"), // variant
Token::Struct {
len: 2,
@@ -2757,11 +2851,33 @@ mod flatten {
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// extra
Token::Str("extra_key"),
Token::Str("extra value"),
// data
Token::Str("Struct"), // variant
Token::Struct {
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
Token::MapEnd,
],
);
}
}
@@ -2782,6 +2898,7 @@ mod flatten {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "tag", content = "content")]
enum Enum {
Unit,
Newtype(NewtypeVariant),
Struct { index: u32, value: u32 },
}
@@ -2792,24 +2909,357 @@ mod flatten {
}
#[test]
fn struct_() {
fn unit() {
let value = Flatten {
outer: 42,
data: NewtypeWrapper(Enum::Unit),
};
// Field order: outer, [tag]
assert_tokens(
&Flatten {
outer: 42,
data: NewtypeWrapper(Enum::Struct {
index: 0,
value: 42,
}),
},
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// content missing
Token::MapEnd,
],
);
// Field order: [tag], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// content missing
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: outer, [tag, content]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// content
Token::Str("content"),
Token::Unit,
Token::MapEnd,
],
);
// Field order: outer, [content, tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Unit,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
Token::MapEnd,
],
);
// Field order: [tag, content], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// content
Token::Str("content"),
Token::Unit,
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [content, tag], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Unit,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [tag], outer, [content]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Unit,
Token::MapEnd,
],
);
// Field order: [content], outer, [tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Unit,
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Unit",
},
Token::MapEnd,
],
);
}
#[test]
fn newtype() {
let value = Flatten {
outer: 42,
data: NewtypeWrapper(Enum::Newtype(NewtypeVariant { value: 23 })),
};
// Field order: outer, [tag, content]
assert_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
Token::MapEnd,
],
);
// Field order: outer, [content, tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
Token::MapEnd,
],
);
// Field order: [tag, content], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [content, tag], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [tag], outer, [content]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
Token::MapEnd,
],
);
// Field order: [content], outer, [tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
},
Token::Str("value"),
Token::U32(23),
Token::StructEnd,
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
},
Token::MapEnd,
],
);
}
#[test]
fn struct_() {
let value = Flatten {
outer: 42,
data: NewtypeWrapper(Enum::Struct {
index: 0,
value: 42,
}),
};
// Field order: outer, [tag, content]
assert_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Struct",
},
// content
Token::Str("content"),
Token::Struct {
len: 2,
@@ -2823,32 +3273,143 @@ mod flatten {
Token::MapEnd,
],
);
}
#[test]
fn newtype() {
assert_tokens(
&Flatten {
outer: 42,
data: NewtypeWrapper(Enum::Newtype(NewtypeVariant { value: 23 })),
},
// Field order: outer, [content, tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Struct {
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Newtype",
variant: "Struct",
},
Token::MapEnd,
],
);
// Field order: [tag, content], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Struct",
},
// content
Token::Str("content"),
Token::Struct {
len: 1,
name: "NewtypeVariant",
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(23),
Token::U32(42),
Token::StructEnd,
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [content, tag], outer
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Struct {
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Struct",
},
// outer
Token::Str("outer"),
Token::U32(42),
Token::MapEnd,
],
);
// Field order: [tag], outer, [content]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Struct",
},
// outer
Token::Str("outer"),
Token::U32(42),
// content
Token::Str("content"),
Token::Struct {
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
Token::MapEnd,
],
);
// Field order: [content], outer, [tag]
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// content
Token::Str("content"),
Token::Struct {
len: 2,
name: "Struct",
},
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
// outer
Token::Str("outer"),
Token::U32(42),
// tag
Token::Str("tag"),
Token::UnitVariant {
name: "Enum",
variant: "Struct",
},
Token::MapEnd,
],
);
@@ -2882,17 +3443,20 @@ mod flatten {
D { d: i32 },
}
let value = Flatten {
x: X::B { b: 1 },
y: Y::D { d: 2 },
};
assert_tokens(
&Flatten {
x: X::B { b: 1 },
y: Y::D { d: 2 },
},
&value,
&[
Token::Map { len: None },
// x
Token::Str("typeX"),
Token::Str("B"),
Token::Str("b"),
Token::I32(1),
// y
Token::Str("typeY"),
Token::Str("D"),
Token::Str("d"),
@@ -2900,11 +3464,28 @@ mod flatten {
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// y
Token::Str("typeY"),
Token::Str("D"),
Token::Str("d"),
Token::I32(2),
// x
Token::Str("typeX"),
Token::Str("B"),
Token::Str("b"),
Token::I32(1),
Token::MapEnd,
],
);
}
#[test]
fn unit_enum_with_unknown_fields() {
#[derive(Debug, PartialEq, Deserialize)]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Flatten {
#[serde(flatten)]
x: X,
@@ -2912,31 +3493,49 @@ mod flatten {
y: Y,
}
#[derive(Debug, PartialEq, Deserialize)]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "typeX")]
enum X {
A,
}
#[derive(Debug, PartialEq, Deserialize)]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "typeY")]
enum Y {
B { c: u32 },
}
assert_de_tokens(
&Flatten {
x: X::A,
y: Y::B { c: 0 },
},
let value = Flatten {
x: X::A,
y: Y::B { c: 0 },
};
assert_tokens(
&value,
&[
Token::Map { len: None },
// x
Token::Str("typeX"),
Token::Str("A"),
// y
Token::Str("typeY"),
Token::Str("B"),
Token::Str("c"),
Token::I32(0),
Token::U32(0),
Token::MapEnd,
],
);
assert_de_tokens(
&value,
&[
Token::Map { len: None },
// y
Token::Str("typeY"),
Token::Str("B"),
Token::Str("c"),
Token::U32(0),
// x
Token::Str("typeX"),
Token::Str("A"),
Token::MapEnd,
],
);
+4 -1
View File
@@ -1,7 +1,10 @@
#![allow(
clippy::derive_partial_eq_without_eq,
clippy::items_after_statements,
clippy::used_underscore_binding
clippy::used_underscore_binding,
// We use lots of declarations inside function bodies to avoid conflicts,
// but they aren't used. We just want to make sure they compile.
dead_code,
)]
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
+3 -4
View File
@@ -2,7 +2,7 @@
clippy::cast_lossless,
clippy::decimal_literal_representation,
clippy::derive_partial_eq_without_eq,
clippy::empty_enum,
clippy::empty_enums,
clippy::manual_assert,
clippy::needless_pass_by_value,
clippy::uninlined_format_args,
@@ -10,7 +10,6 @@
)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use fnv::FnvHasher;
use serde::de::value::{F32Deserializer, F64Deserializer};
use serde::de::{Deserialize, DeserializeOwned, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
@@ -1040,7 +1039,7 @@ fn test_hashset() {
],
);
test(
hashset![FnvHasher @ 1, 2, 3],
hashset![foldhash::fast::FixedState; 1, 2, 3],
&[
Token::Seq { len: Some(3) },
Token::I32(1),
@@ -1275,7 +1274,7 @@ fn test_hashmap() {
],
);
test(
hashmap![FnvHasher @ 1 => 2, 3 => 4],
hashmap![foldhash::fast::FixedState; 1 => 2, 3 => 4],
&[
Token::Map { len: Some(2) },
Token::I32(1),
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(
clippy::derive_partial_eq_without_eq,
clippy::empty_enum,
clippy::empty_enums,
clippy::unreadable_literal
)]
#![cfg_attr(feature = "unstable", feature(never_type))]
+30
View File
@@ -0,0 +1,30 @@
#![deny(deprecated)]
#![allow(dead_code)]
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[deprecated]
enum DeprecatedEnum {
A,
B,
}
#[derive(Serialize, Deserialize)]
#[deprecated]
struct DeprecatedStruct {
a: bool,
}
#[derive(Serialize, Deserialize)]
enum DeprecatedVariant {
A,
#[deprecated]
B,
}
#[derive(Serialize, Deserialize)]
struct DeprecatedField {
#[deprecated]
a: bool,
}
+14 -6
View File
@@ -18,7 +18,10 @@
clippy::ptr_arg,
clippy::too_many_lines,
clippy::trivially_copy_pass_by_ref,
clippy::type_repetition_in_bounds
clippy::type_repetition_in_bounds,
// We use lots of declarations inside function bodies to avoid conflicts,
// but they aren't used. We just want to make sure they compile.
dead_code,
)]
#![deny(clippy::collection_is_never_read)]
@@ -689,6 +692,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
#[allow(dead_code)]
pub enum UntaggedNewtypeVariantWith {
Newtype(
#[serde(serialize_with = "ser_x")]
@@ -699,6 +703,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
#[allow(dead_code)]
pub struct TransparentWith {
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
@@ -707,6 +712,7 @@ fn test_gen() {
#[derive(Deserialize)]
#[serde(untagged)]
#[allow(dead_code)]
pub enum UntaggedWithBorrow<'a> {
Single(
#[serde(borrow)]
@@ -769,7 +775,7 @@ fn test_gen() {
}
#[derive(Serialize)]
#[repr(packed)]
#[repr(C, packed)]
#[allow(dead_code)]
struct Packed {
x: u8,
@@ -805,6 +811,8 @@ fn test_gen() {
pub vec: Vec<Self>,
}
assert_ser::<Struct>();
#[derive(Deserialize)]
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
pub struct GenericUnitStruct<const N: usize>;
@@ -915,14 +923,14 @@ where
//////////////////////////////////////////////////////////////////////////
#[repr(packed)]
#[repr(C, packed)]
pub struct RemotePacked {
pub a: u16,
pub b: u32,
}
#[derive(Serialize)]
#[repr(packed)]
#[repr(C, packed)]
#[serde(remote = "RemotePacked")]
pub struct RemotePackedDef {
a: u16,
@@ -933,14 +941,14 @@ impl Drop for RemotePackedDef {
fn drop(&mut self) {}
}
#[repr(packed)]
#[repr(C, packed)]
pub struct RemotePackedNonCopy {
pub a: u16,
pub b: String,
}
#[derive(Deserialize)]
#[repr(packed)]
#[repr(C, packed)]
#[serde(remote = "RemotePackedNonCopy")]
pub struct RemotePackedNonCopyDef {
a: u16,
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(clippy::redundant_field_names)]
#![allow(clippy::redundant_field_names, dead_code)]
use serde_derive::{Deserialize, Serialize};
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(clippy::used_underscore_binding)]
#![allow(clippy::used_underscore_binding, dead_code)]
use serde_derive::{Deserialize, Serialize};
+2 -3
View File
@@ -1,7 +1,6 @@
#![allow(clippy::derive_partial_eq_without_eq, clippy::unreadable_literal)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use fnv::FnvHasher;
use serde_derive::Serialize;
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
use std::cell::RefCell;
@@ -220,7 +219,7 @@ fn test_hashset() {
&[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd],
);
assert_ser_tokens(
&hashset![FnvHasher @ 1],
&hashset![foldhash::fast::FixedState; 1],
&[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd],
);
}
@@ -300,7 +299,7 @@ fn test_hashmap() {
],
);
assert_ser_tokens(
&hashmap![FnvHasher @ 1 => 2],
&hashmap![foldhash::fast::FixedState; 1 => 2],
&[
Token::Map { len: Some(1) },
Token::I32(1),
+2
View File
@@ -1,5 +1,7 @@
#![allow(
clippy::elidable_lifetime_names,
clippy::extra_unused_type_parameters,
clippy::needless_lifetimes,
clippy::type_repetition_in_bounds
)]
@@ -0,0 +1,75 @@
#![allow(non_camel_case_types)]
use serde_derive::Deserialize;
#[derive(Deserialize)]
enum E {
S1 {
#[serde(alias = "a", alias = "b", alias = "c")]
a: (),
// Warning on "c" and "b"
#[serde(alias = "c")]
b: (),
#[serde(skip_deserializing)]
c: (),
},
S2 {
#[serde(alias = "b", alias = "c")]
a: (),
// Warning on "c"
#[serde(rename = "c")]
b: (),
},
#[serde(rename_all = "UPPERCASE")]
S3 {
#[serde(alias = "B", alias = "c")]
a: (),
// Warning on "b" because this collides with the "B" above after
// applying rename rules
b: (),
},
}
#[derive(Deserialize)]
enum E1 {
#[serde(alias = "a", alias = "b", alias = "c")]
a,
// Warning on "c" and "b"
#[serde(alias = "c")]
b,
#[serde(skip_deserializing)]
c,
}
#[derive(Deserialize)]
enum E2 {
#[serde(alias = "b", alias = "c")]
a,
// Warning on "c"
#[serde(rename = "c")]
b,
}
#[derive(Deserialize)]
#[serde(rename_all = "UPPERCASE")]
enum E3 {
#[serde(alias = "B", alias = "c")]
a,
// Warning on "b" because this collides with the "B" above after applying
// rename rules
b,
}
fn main() {
__FAIL__;
}
@@ -0,0 +1,79 @@
error[E0425]: cannot find value `__FAIL__` in this scope
--> tests/ui/conflict/alias-enum.rs:74:5
|
74 | __FAIL__;
| ^^^^^^^^ not found in this scope
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:13:9
|
8 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
13 | b: (),
| ^ no value can reach this
|
= note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:12:25
|
8 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
12 | #[serde(alias = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:24:26
|
20 | #[serde(alias = "b", alias = "c")]
| --- matches all the relevant values
...
24 | #[serde(rename = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:35:9
|
30 | #[serde(alias = "B", alias = "c")]
| --- matches all the relevant values
...
35 | b: (),
| ^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:46:5
|
41 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
46 | b,
| ^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:45:21
|
41 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
45 | #[serde(alias = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:58:22
|
54 | #[serde(alias = "b", alias = "c")]
| --- matches all the relevant values
...
58 | #[serde(rename = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias-enum.rs:70:5
|
65 | #[serde(alias = "B", alias = "c")]
| --- matches all the relevant values
...
70 | b,
| ^ no value can reach this
+39
View File
@@ -0,0 +1,39 @@
use serde_derive::Deserialize;
#[derive(Deserialize)]
struct S1 {
#[serde(alias = "a", alias = "b", alias = "c")]
a: (),
// Warning on "c" and "b"
#[serde(alias = "c")]
b: (),
#[serde(skip_deserializing)]
c: (),
}
#[derive(Deserialize)]
struct S2 {
#[serde(alias = "b", alias = "c")]
a: (),
// Warning on "c"
#[serde(rename = "c")]
b: (),
}
#[derive(Deserialize)]
#[serde(rename_all = "UPPERCASE")]
struct S3 {
#[serde(alias = "B", alias = "c")]
a: (),
// Warning on "b" because this collides with the "B" above after applying
// rename rules
b: (),
}
fn main() {
__FAIL__;
}
+43
View File
@@ -0,0 +1,43 @@
error[E0425]: cannot find value `__FAIL__` in this scope
--> tests/ui/conflict/alias.rs:38:5
|
38 | __FAIL__;
| ^^^^^^^^ not found in this scope
warning: unreachable pattern
--> tests/ui/conflict/alias.rs:10:5
|
5 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
10 | b: (),
| ^ no value can reach this
|
= note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
warning: unreachable pattern
--> tests/ui/conflict/alias.rs:9:21
|
5 | #[serde(alias = "a", alias = "b", alias = "c")]
| --- matches all the relevant values
...
9 | #[serde(alias = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias.rs:22:22
|
18 | #[serde(alias = "b", alias = "c")]
| --- matches all the relevant values
...
22 | #[serde(rename = "c")]
| ^^^ no value can reach this
warning: unreachable pattern
--> tests/ui/conflict/alias.rs:34:5
|
29 | #[serde(alias = "B", alias = "c")]
| --- matches all the relevant values
...
34 | b: (),
| ^ no value can reach this
@@ -1,11 +1,11 @@
error: variant field name `conflict` conflicts with internal tag
--> tests/ui/conflict/internal-tag-alias.rs:4:1
|
4 | / #[serde(tag = "conflict")]
5 | | enum E {
6 | | A {
7 | | #[serde(alias = "conflict")]
8 | | x: (),
9 | | },
4 | / #[serde(tag = "conflict")]
5 | | enum E {
6 | | A {
7 | | #[serde(alias = "conflict")]
8 | | x: (),
9 | | },
10 | | }
| |_^
@@ -1,11 +1,11 @@
error: variant field name `conflict` conflicts with internal tag
--> tests/ui/conflict/internal-tag.rs:4:1
|
4 | / #[serde(tag = "conflict")]
5 | | enum E {
6 | | A {
7 | | #[serde(rename = "conflict")]
8 | | x: (),
9 | | },
4 | / #[serde(tag = "conflict")]
5 | | enum E {
6 | | A {
7 | | #[serde(rename = "conflict")]
8 | | x: (),
9 | | },
10 | | }
| |_^
@@ -0,0 +1,20 @@
// Tests that type error points to the path in attribute
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
enum Enum {
// Newtype variants do not use the provided path, so it is forbidden here
// Newtype(#[serde(default = "main")] u8),
Tuple(u8, #[serde(default = "main")] i8),
Struct {
#[serde(default = "main")]
f1: u8,
f2: u8,
#[serde(default = "main")]
f3: i8,
},
}
fn main() {}
@@ -0,0 +1,35 @@
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:10:33
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `i8`
| `match` arms have incompatible types
...
10 | Tuple(u8, #[serde(default = "main")] i8),
| ^^^^^^ expected `i8`, found `()`
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:12:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `u8`
| `match` arms have incompatible types
...
12 | #[serde(default = "main")]
| ^^^^^^ expected `u8`, found `()`
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:15:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `i8`
| `match` arms have incompatible types
...
15 | #[serde(default = "main")]
| ^^^^^^ expected `i8`, found `()`
@@ -0,0 +1,19 @@
// Tests that type error points to the path in attribute
use serde_derive::Deserialize;
#[derive(Deserialize)]
enum Enum {
// Newtype variants do not use the provided path, so it is forbidden here
// Newtype(#[serde(default = "main")] u8),
Tuple(u8, #[serde(default = "main")] i8),
Struct {
#[serde(default = "main")]
f1: u8,
f2: u8,
#[serde(default = "main")]
f3: i8,
},
}
fn main() {}
@@ -0,0 +1,35 @@
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:9:33
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `i8`
| `match` arms have incompatible types
...
9 | Tuple(u8, #[serde(default = "main")] i8),
| ^^^^^^ expected `i8`, found `()`
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:11:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `u8`
| `match` arms have incompatible types
...
11 | #[serde(default = "main")]
| ^^^^^^ expected `u8`, found `()`
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:14:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `i8`
| `match` arms have incompatible types
...
14 | #[serde(default = "main")]
| ^^^^^^ expected `i8`, found `()`
@@ -0,0 +1,20 @@
// Tests that type error points to the path in attribute
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(tag = "tag")]
enum Enum {
// Newtype variants do not use the provided path, so it is forbidden here
// Newtype(#[serde(default = "main")] u8),
// Tuple variants are not supported in internally tagged enums
Struct {
#[serde(default = "main")]
f1: u8,
f2: u8,
#[serde(default = "main")]
f3: i8,
},
}
fn main() {}
@@ -0,0 +1,23 @@
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:12:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `u8`
| `match` arms have incompatible types
...
12 | #[serde(default = "main")]
| ^^^^^^ expected `u8`, found `()`
error[E0308]: `match` arms have incompatible types
--> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:15:27
|
5 | #[derive(Deserialize)]
| -----------
| |
| this is found to be of type `i8`
| `match` arms have incompatible types
...
15 | #[serde(default = "main")]
| ^^^^^^ expected `i8`, found `()`
@@ -0,0 +1,20 @@
// Tests that type error points to the path in attribute
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(untagged)]
enum Enum {
// Newtype variants do not use the provided path, so it is forbidden here
// Newtype(#[serde(default = "main")] u8),
Tuple(u8, #[serde(default = "main")] i8),
Struct {
#[serde(default = "main")]
f1: u8,
f2: u8,
#[serde(default = "main")]
f3: i8,
},
}
fn main() {}

Some files were not shown because too many files have changed in this diff Show More