Compare commits

...

163 Commits

Author SHA1 Message Date
David Tolnay 22be673beb Release 1.0.174 2023-07-20 22:20:37 -07:00
David Tolnay 166c89fabf Opt in to generate-link-to-definition when building on docs.rs 2023-07-20 22:19:03 -07:00
David Tolnay 6e0b13eedb Release 1.0.173 2023-07-19 16:34:13 -07:00
David Tolnay 7e8f978ca9 Handle $crate special case 2023-07-19 16:32:59 -07:00
David Tolnay 6c0e838a7c Always consider empty output to be unsuccessful 2023-07-19 16:13:02 -07:00
David Tolnay d3da41927a Enable full expression parsing for precompiled serde_derive 2023-07-19 16:01:18 -07:00
David Tolnay 425a4b7a74 Check precompiled subprocess exit status 2023-07-19 16:00:37 -07:00
David Tolnay 63c65ef742 Release 1.0.172 2023-07-19 14:13:56 -07:00
David Tolnay e838b0bd81 Release 1.0.172-alpha.0 2023-07-19 14:00:50 -07:00
David Tolnay 041e99c78a Implement fallback to compiling serde_derive from source 2023-07-19 13:53:49 -07:00
David Tolnay 07dcc4f7fe Remove unneeded 'include' Cargo.toml entries 2023-07-19 13:44:55 -07:00
David Tolnay b88052d875 Rearrange precompiled directory 2023-07-19 13:24:36 -07:00
David Tolnay a28292764c Publish precompiled deserialize_in_place 2023-07-19 12:29:30 -07:00
David Tolnay 2027088741 Support precompiled deserialize_in_place 2023-07-19 12:27:37 -07:00
David Tolnay e2d8589976 Publish span-related fixes 2023-07-19 09:41:11 -07:00
David Tolnay c8a9f99d14 Preserve Group span better on compilers without Span::join 2023-07-19 09:39:11 -07:00
David Tolnay 645d04012d Fix off by one span counter, 0 is used for call_site() 2023-07-19 09:26:56 -07:00
David Tolnay 100ddada2f Suppress dead_code on fields only accessed by deserialize_in_place
error: field `option` is never read
       --> test_suite/tests/test_gen.rs:666:9
        |
    665 |     struct ImplicitlyBorrowedOption<'a> {
        |            ------------------------ field in this struct
    666 |         option: std::option::Option<&'a str>,
        |         ^^^^^^
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`

    error: fields `ty` and `id` are never read
       --> test_suite/tests/test_gen.rs:696:9
        |
    695 |     struct RelObject<'a> {
        |            --------- fields in this struct
    696 |         ty: &'a str,
        |         ^^
    697 |         id: String,
        |         ^^

    error: field `field` is never read
       --> test_suite/tests/test_gen.rs:740:17
        |
    739 |             struct MacroRules<'a> {
        |                    ---------- field in this struct
    740 |                 field: $field,
        |                 ^^^^^
    ...
    745 |     deriving!(&'a str);
        |     ------------------ in this macro invocation
        |
        = note: this error originates in the macro `deriving` (in Nightly builds, run with -Z macro-backtrace for more info)

    error: field `f` is never read
       --> test_suite/tests/test_gen.rs:756:9
        |
    754 |     struct BorrowLifetimeInsideMacro<'a> {
        |            ------------------------- field in this struct
    755 |         #[serde(borrow = "'a")]
    756 |         f: mac!(Cow<'a, str>),
        |         ^

    warning: fields `question` and `answer` are never read
        --> test_suite/tests/test_annotations.rs:2969:9
         |
    2968 |     struct Struct {
         |            ------ fields in this struct
    2969 |         question: String,
         |         ^^^^^^^^
    2970 |         answer: u32,
         |         ^^^^^^
         |
         = note: `#[warn(dead_code)]` on by default
2023-07-19 09:12:35 -07:00
David Tolnay 2ef1cd4b35 Import macros exclusively through serde_derive in test suite
This makes it easier to execute tests against the precompiled serde_derive.
2023-07-19 09:08:05 -07:00
David Tolnay be9c3fd69d Publish raw string fix 2023-07-18 18:42:54 -07:00
David Tolnay ef522e1d16 Add a reminder about trim-paths 2023-07-18 18:39:40 -07:00
David Tolnay 1ddb6c2fdb Fix handling of raw idents in proc-macro2 shim 2023-07-18 18:29:24 -07:00
David Tolnay eb3f2329af Merge pull request #2514 from dtolnay/precompiled
Add experiment to produce precompiled builds of serde_derive
2023-07-18 13:48:17 -07:00
David Tolnay 9e8f14816b Add experiment to produce precompiled builds of serde_derive 2023-07-18 13:37:36 -07:00
David Tolnay 03da66c805 Release 1.0.171 2023-07-09 18:05:02 -07:00
David Tolnay f75426f47e Inline visitor_expr of unit struct deserialize impl 2023-07-09 18:03:58 -07:00
David Tolnay 662fc3861c Add test of const-generic unit struct where-clause edge case
Closes #2501.
2023-07-09 18:01:43 -07:00
David Tolnay 28c10020b9 Merge pull request #2500 from Baptistemontan/derive_generic_unit_struct
Allow `[derive(serde::Deserialize)]` for generic unit structs
2023-07-09 17:52:12 -07:00
Baptiste de Montangon 89c8d85de9 allow Deserialize derive to handle generic unit structs 2023-07-10 01:31:40 +02:00
David Tolnay 6502838f27 Release 1.0.170 2023-07-09 11:17:30 -07:00
David Tolnay c93a0f335a Merge pull request #2499 from dtolnay/strsuffix
Reject suffixed string literals inside serde attrs
2023-07-09 11:16:31 -07:00
David Tolnay 8264e002a7 Reject suffixed string literals inside serde attrs 2023-07-09 11:13:24 -07:00
David Tolnay 117ef22142 Add ui test with suffixed string literals in attribute 2023-07-09 11:09:38 -07:00
David Tolnay 3fb5e71c33 Release 1.0.169 2023-07-08 21:09:08 -07:00
David Tolnay 296db177e2 Pull in syn fix for issue 2414 2023-07-08 21:08:22 -07:00
David Tolnay e4a4389177 Delete excessive tests of adjacently tagged non-string keys 2023-07-08 18:23:31 -07:00
David Tolnay 7aa0453c3b Merge pull request 2475 from Baptistemontan/master 2023-07-08 18:07:16 -07:00
David Tolnay 09b78b24e9 Release 1.0.168 2023-07-08 17:52:06 -07:00
David Tolnay a622b8a74a Merge pull request #2495 from dtolnay/cautious
Allow larger preallocated capacity for smaller elements
2023-07-08 17:51:16 -07:00
David Tolnay 399ef081ec Allow larger preallocated capacity for smaller elements 2023-07-08 17:43:01 -07:00
David Tolnay 3686277e14 Merge pull request #2436 from Mingun/flatten-ignored-any
Allow to flatten `IgnoredAny`
2023-07-06 16:35:10 -07:00
David Tolnay 807bd20a64 Release 1.0.167 2023-07-06 16:25:48 -07:00
David Tolnay ed9a140348 Merge pull request #2444 from Mingun/dedup
Simplify code for generation of struct deserializers
2023-07-06 16:25:15 -07:00
David Tolnay 2de7c2bea2 Resolve redundant_static_lifetimes clippy lint from PR 2471
error: constants have by default a `'static` lifetime
        --> serde/src/de/impls.rs:2467:24
         |
    2467 |     pub const FIELDS: &'static [&'static str] = &["end"];
         |                       -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
         = note: `-D clippy::redundant-static-lifetimes` implied by `-D clippy::all`

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

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

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

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

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

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

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

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

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

- move A and D down

or:

- move B, C, and E up.

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

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

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

    Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)...
    fatal error: failed to build sysroot; run `cargo miri setup` to see the error details
2023-05-23 08:29:47 -07:00
David Tolnay fccb9499bc Release 1.0.163 2023-05-10 00:47:53 -07:00
David Tolnay a139ab2572 Adjust PR 2446 with less overgeneralized name 2023-05-10 00:45:52 -07:00
David Tolnay 1d910a484c Format with rustfmt 1.5.2-nightly 2023-05-10 00:40:39 -07:00
David Tolnay ee9166ec97 Revise comments on the FlatMapDeserializer entry taker 2023-05-10 00:39:10 -07:00
David Tolnay b5a9eff32e Resolve while_let_on_iterator clippy lint
warning: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2905:9
         |
    2905 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in self.iter.by_ref()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
         = note: `#[warn(clippy::while_let_on_iterator)]` on by default
2023-05-10 00:23:38 -07:00
David Tolnay 9441a29663 Merge pull request #2446 from Mingun/dedup2
Eliminate some duplicated code
2023-05-10 00:13:44 -07:00
Mingun ab6588ef74 Extract duplicated code into a function 2023-05-08 10:39:30 +05:00
Mingun 1d11f03449 Extract logic of taking flattened fields into a function 2023-05-08 10:39:27 +05:00
Mingun e11d01fe1d Remove constructors for FlatMapAccess and FlatStructAccess
They are used only in one place each, so for simplifying understanding it is better to inline them
2023-05-08 09:40:06 +05:00
Mingun a901f50850 FlatMapAccess and FlatStructAccess does not need to be public 2023-05-08 09:37:15 +05:00
Mingun c399e9c368 Remove FlatInternallyTaggedAccess because it is the same as FlatMapAccess 2023-05-08 09:25:18 +05:00
David Tolnay 25381be0c9 Merge pull request #2442 from taiki-e/derive-build-script
Remove build script from serde_derive
2023-05-05 14:35:09 -07:00
Taiki Endo ef2a7c753f Remove build script from serde_derive
The current serde_derive's MSRV is 1.56, and both underscore consts and
ptr::addr_of! are always available.
2023-05-06 05:34:38 +09:00
David Tolnay 99f165b45a Release 1.0.162 2023-05-04 18:46:55 -07:00
David Tolnay 2fb5560746 Attempt to generate just one copy of TagContentOtherFieldVisitor's field matching 2023-05-04 18:42:21 -07:00
David Tolnay bd653ab30c Format PR 2377 with rustfmt 2023-05-04 18:42:21 -07:00
David Tolnay b5d68aedaa Merge pull request #2377 from mfro/master
Allow bytes for adjacently tagged enums
2023-05-04 18:39:57 -07:00
David Tolnay 624879c4c6 Merge pull request #2441 from dtolnay/test
Reimplement tests that touched serde_test internal API
2023-05-04 17:42:07 -07:00
David Tolnay bd9e9abf35 Reimplement tests that touched serde_test internal API 2023-05-04 17:38:58 -07:00
David Tolnay 3e4a23cbd0 Release 1.0.161 2023-05-04 16:45:18 -07:00
David Tolnay 6326ceec3f Don't panic in serde_test on running out of tokens 2023-05-04 16:38:20 -07:00
David Tolnay 8f4d37c7ec Convert serde_test's assert_next_token from macro to function 2023-05-04 16:34:14 -07:00
David Tolnay 1b8290b318 Convert serde_test's unexpected from macro to function 2023-05-04 16:30:34 -07:00
David Tolnay 48193fbccd Merge pull request #2435 from Mingun/hitchhiker-guide
Don't panic in serde_test
2023-05-04 16:27:35 -07:00
Mingun 51799dd654 Allow to flatten IgnoredAny to ignore any additional data
Although any additional fields in struct by default are ignored, sometimes
this can be useful, if you use generic structures, for example
2023-04-30 01:59:55 +05:00
Mingun 732ac49321 Implement PartialEq for IgnoredAny so it can be used in tests 2023-04-30 01:58:07 +05:00
Mingun ac8ea72d88 Don't panic in serde_test
Panics lead to reporting errors in tests inside of serde_test internals,
returning errors moves the report location to the corresponding assert_tokens
expression
2023-04-30 00:06:51 +05:00
David Tolnay f583401284 Merge pull request #2433 from Mingun/rm-gitattributes
Remove unused after .gitattributes
2023-04-26 12:04:04 -07:00
Mingun 2d88228b7d Remove unused after a649190a4d .gitattributes 2023-04-26 23:54:09 +05:00
David Tolnay 0c6a2bbf79 Release 1.0.160 2023-04-10 22:15:49 -07:00
David Tolnay a80d830f27 Merge pull request #2426 from compiler-errors/dont-doc-private
Make derived serializer/deserializer internals `doc(hidden)`
2023-04-10 22:12:35 -07:00
Michael Goulet 5f3fd9994e Make serializer/deserializer internals doc(hidden) 2023-04-10 21:41:50 -07:00
David Tolnay d6de911855 Release 1.0.159 2023-03-27 22:05:58 -07:00
David Tolnay 04af32230e Merge pull request #2422 from dtolnay/emptyattr
Accept empty #[serde()] attribute
2023-03-27 22:05:18 -07:00
David Tolnay 4cb8d079f8 Accept empty #[serde()] attribute 2023-03-27 22:00:46 -07:00
David Tolnay 6ab55a1e52 Add regression test for issue 2415
Currently fails:

    error: unexpected end of input, unexpected token in nested attribute, expected ident
     --> test_suite/tests/regression/issue2415.rs:4:9
      |
    4 | #[serde()]
      |         ^
2023-03-27 22:00:01 -07:00
David Tolnay acfd19cb46 Release serde_derive_internals 0.27.0 2023-03-20 04:32:49 -07:00
David Tolnay e3058105f0 Release 1.0.158 2023-03-20 04:24:27 -07:00
David Tolnay dc200a6450 Reformat comments of non-public serde_derive internals
Fixes these being treated as "tests" by `cargo test` in serde_derive:

    running 3 tests
    test src/internals/check.rs - internals::check::check_remote_generic (line 23) ... FAILED
    test src/internals/check.rs - internals::check::check_remote_generic (line 29) ... FAILED
    test src/lib.rs - (line 3) ... ok

    failures:

    ---- src/internals/check.rs - internals::check::check_remote_generic (line 23) stdout ----
    error: unknown start of token: \u{2026}
     --> src/internals/check.rs:25:20
      |
    4 | struct Generic<T> {…}
      |                    ^

    error: cannot find attribute `serde` in this scope
     --> src/internals/check.rs:24:3
      |
    3 | #[serde(remote = "Generic")]
      |   ^^^^^
      |
      = note: `serde` is in scope, but it is a crate, not an attribute

    error[E0392]: parameter `T` is never used
     --> src/internals/check.rs:25:16
      |
    4 | struct Generic<T> {…}
      |                ^ unused parameter
      |
      = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
      = help: if you intended `T` to be a const parameter, use `const T: usize` instead

    ---- src/internals/check.rs - internals::check::check_remote_generic (line 29) stdout ----
    error: unknown start of token: \u{2026}
     --> src/internals/check.rs:31:21
      |
    4 | struct ConcreteDef {…}
      |                     ^

    error: cannot find attribute `serde` in this scope
     --> src/internals/check.rs:30:3
      |
    3 | #[serde(remote = "Generic<T>")]
      |   ^^^^^
      |
      = note: `serde` is in scope, but it is a crate, not an attribute
2023-03-20 04:23:46 -07:00
David Tolnay 2c0999a0b9 Merge pull request #2410 from serde-rs/attrvalue
Check for None-delimited group in attribute value
2023-03-20 04:23:33 -07:00
David Tolnay dd460f82a1 Check for None-delimited group in attribute value 2023-03-20 04:16:52 -07:00
David Tolnay c3d637f397 Add regression test for issue 2409 2023-03-20 03:59:43 -07:00
David Tolnay 479a00a215 Release 1.0.157 2023-03-17 17:35:09 -07:00
David Tolnay c42e7c8012 Reflect serde_derive required compiler in build script and rust-version metadata 2023-03-17 17:34:46 -07:00
David Tolnay 5b8e0657d4 Ignore single_match_else pedantic clippy lint in serde_derive_internals
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
        --> serde_derive_internals/src/attr.rs:1412:8
         |
    1412 |       Ok(match string.parse() {
         |  ________^
    1413 | |         Ok(path) => Some(path),
    1414 | |         Err(_) => {
    1415 | |             cx.error_spanned_by(
    ...    |
    1420 | |         }
    1421 | |     })
         | |_____^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
         = note: `-D clippy::single-match-else` implied by `-D clippy::pedantic`
    help: try this
         |
    1412 ~     Ok(if let Ok(path) = string.parse() { Some(path) } else {
    1413 +         cx.error_spanned_by(
    1414 +             &string,
    1415 +             format!("failed to parse path: {:?}", string.value()),
    1416 +         );
    1417 +         None
    1418 ~     })
         |

    error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
        --> serde_derive_internals/src/attr.rs:1434:8
         |
    1434 |       Ok(match string.parse() {
         |  ________^
    1435 | |         Ok(expr) => Some(expr),
    1436 | |         Err(_) => {
    1437 | |             cx.error_spanned_by(
    ...    |
    1442 | |         }
    1443 | |     })
         | |_____^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
    help: try this
         |
    1434 ~     Ok(if let Ok(expr) = string.parse() { Some(expr) } else {
    1435 +         cx.error_spanned_by(
    1436 +             &string,
    1437 +             format!("failed to parse path: {:?}", string.value()),
    1438 +         );
    1439 +         None
    1440 ~     })
         |

    error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
        --> serde_derive_internals/src/attr.rs:1478:8
         |
    1478 |       Ok(match string.parse() {
         |  ________^
    1479 | |         Ok(ty) => Some(ty),
    1480 | |         Err(_) => {
    1481 | |             cx.error_spanned_by(
    ...    |
    1486 | |         }
    1487 | |     })
         | |_____^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
    help: try this
         |
    1478 ~     Ok(if let Ok(ty) = string.parse() { Some(ty) } else {
    1479 +         cx.error_spanned_by(
    1480 +             &string,
    1481 +             format!("failed to parse type: {} = {:?}", attr_name, string.value()),
    1482 +         );
    1483 +         None
    1484 ~     })
         |
2023-03-17 17:32:50 -07:00
David Tolnay 9fc0d13e2c Merge pull request #2406 from dtolnay/nestedmeta
Rewrite attribute parser using parse_nested_meta
2023-03-17 17:32:39 -07:00
David Tolnay bc22641359 Rewrite attribute parser using parse_nested_meta 2023-03-17 17:23:56 -07:00
David Tolnay 05098105a8 Update compiler version for serde_derive in readme 2023-03-17 17:23:33 -07:00
David Tolnay 5b23634dc6 Merge pull request #2405 from dtolnay/syn
Update to syn 2
2023-03-17 17:23:20 -07:00
David Tolnay 32f0d00ff9 Update to syn 2 2023-03-17 17:17:40 -07:00
David Tolnay 9d87851f0c Merge pull request #2404 from dtolnay/attributeexpr
Add ui test of malformed attribute containing expression
2023-03-17 17:14:54 -07:00
David Tolnay c0296ee11b Add ui test of malformed attribute containing expression 2023-03-16 00:15:54 -07:00
David Tolnay 54671259aa Release 1.0.156 2023-03-14 01:02:18 -07:00
David Tolnay 994f7c7924 Format with rustfmt 1.5.2-nightly 2023-03-14 00:50:38 -07:00
David Tolnay 7a8e4977e2 Merge pull request #2401 from dtolnay/docderive
Show derive macros in serde's rustdoc
2023-03-14 00:37:06 -07:00
David Tolnay fb7b6ea7ea Enable serde derive feature when built by docs.rs 2023-03-14 00:33:41 -07:00
David Tolnay 063dd5b93f Show derive macros in serde's rustdoc 2023-03-14 00:28:20 -07:00
David Tolnay a38aa31ade Merge pull request #2400 from Nilstrieb/explicit-reexport
Use explicit re-export of `serde_derive` to give rustc more info
2023-03-14 00:26:01 -07:00
nils f42b2581da Use explicit re-export of serde_derive to give rustc more info
rustc will start looking behind `#[cfg(FALSE)]` items to start giving
better diagnostics. By using an explicit re-export instead of a glob
export, we tell rustc that `Deserialize` and `Serialize` exist here.
2023-03-14 08:11:38 +01:00
Max Froehlich a803ec1c1f Allow bytes for adjantly tagged enums 2023-02-18 12:49:23 -08:00
112 changed files with 3942 additions and 1757 deletions
-1
View File
@@ -1 +0,0 @@
test_suite/tests/expand/*.expanded.rs linguist-generated
+14 -2
View File
@@ -3,6 +3,7 @@ name: CI
on:
push:
pull_request:
workflow_dispatch:
schedule: [cron: "40 1 * * *"]
permissions:
@@ -108,12 +109,12 @@ jobs:
- run: cd serde && cargo build
derive:
name: Rust 1.31.0
name: Rust 1.56.0
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.31.0
- uses: dtolnay/rust-toolchain@1.56.0
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
@@ -127,6 +128,16 @@ jobs:
- uses: dtolnay/rust-toolchain@1.36.0
- run: cd serde && cargo build --no-default-features --features alloc
minimal:
name: Minimal versions
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly
- run: cargo generate-lockfile -Z minimal-versions
- run: cargo check --locked --workspace
clippy:
name: Clippy
runs-on: ubuntu-latest
@@ -149,6 +160,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@miri
- run: cargo miri setup
- run: cd serde && cargo miri test --features derive,rc,unstable
env:
MIRIFLAGS: -Zmiri-strict-provenance
+4 -4
View File
@@ -1,13 +1,13 @@
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.19+]][Rust 1.19] [![serde_derive: rustc 1.31+]][Rust 1.31]
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.19+]][Rust 1.19] [![serde_derive: rustc 1.56+]][Rust 1.56]
[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
[Latest Version]: https://img.shields.io/crates/v/serde.svg
[crates.io]: https://crates.io/crates/serde
[serde: rustc 1.19+]: https://img.shields.io/badge/serde-rustc_1.19+-lightgray.svg
[serde_derive: rustc 1.31+]: https://img.shields.io/badge/serde_derive-rustc_1.31+-lightgray.svg
[serde_derive: rustc 1.56+]: https://img.shields.io/badge/serde_derive-rustc_1.56+-lightgray.svg
[Rust 1.19]: https://blog.rust-lang.org/2017/07/20/Rust-1.19.html
[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
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
@@ -48,7 +48,7 @@ serde_json = "1.0"
<p></p>
```rust
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
+1 -1
View File
@@ -16,7 +16,7 @@ You may be looking for:
## Serde in action
```rust
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
+1
View File
@@ -0,0 +1 @@
/serde_derive/serde_derive-x86_64-unknown-linux-gnu
+14
View File
@@ -0,0 +1,14 @@
[workspace]
members = ["bin", "proc-macro2"]
resolver = "2"
[patch.crates-io]
proc-macro2 = { path = "proc-macro2" }
[profile.precompiled]
inherits = "release"
codegen-units = 1
lto = true
opt-level = "z"
panic = "abort"
strip = true
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "serde_derive"
version = "1.0.174"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
[lib]
doctest = false
[[bin]]
name = "serde_derive"
path = "main.rs"
[dependencies]
proc-macro2 = "1"
quote = { version = "1", default-features = false }
syn = { version = "2.0.25", default-features = false, features = ["clone-impls", "derive", "full", "parsing", "printing"] }
+4
View File
@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rustc-cfg=precompiled");
println!("cargo:rustc-cfg=feature=\"deserialize_in_place\"");
}
+27
View File
@@ -0,0 +1,27 @@
extern crate proc_macro2;
use proc_macro2::watt;
use proc_macro2::watt::buffer::InputBuffer;
use std::io::{self, Read, Write};
use std::sync::atomic::Ordering;
fn main() {
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf).unwrap();
let mut buf = InputBuffer::new(&buf);
let derive = match buf.read_u8() {
0 => serde_derive::derive_serialize,
1 => serde_derive::derive_deserialize,
2 => {
serde_derive::DESERIALIZE_IN_PLACE.store(true, Ordering::Relaxed);
serde_derive::derive_deserialize
}
_ => unreachable!(),
};
let input = watt::load(&mut buf);
let output = derive(input);
let bytes = watt::linearize(output);
io::stdout().write_all(&bytes).unwrap();
}
+1
View File
@@ -0,0 +1 @@
../../serde_derive/src
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null
set -e -x
# TODO: Sanitize host filesystem paths. https://github.com/rust-lang/cargo/issues/12137
cargo +nightly build \
--manifest-path bin/Cargo.toml \
--bin serde_derive \
--profile precompiled \
-Z unstable-options \
-Z build-std=std,panic_abort \
-Z build-std-features=panic_immediate_abort \
--target x86_64-unknown-linux-musl \
--out-dir serde_derive
rm -f serde_derive/serde_derive-x86_64-unknown-linux-gnu
mv serde_derive/serde_derive{,-x86_64-unknown-linux-gnu}
#upx --best --lzma serde_derive/serde_derive-x86_64-unknown-linux-gnu
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "proc-macro2"
version = "1.0.66"
edition = "2021"
publish = false
[dependencies]
proc-macro2 = { package = "proc-macro2-fallback", version = "1" }
+815
View File
@@ -0,0 +1,815 @@
#[doc(hidden)]
pub mod watt;
use crate::extra::DelimSpan;
use crate::watt::Identity;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::ops::RangeBounds;
use std::str::FromStr;
pub use proc_macro2::{Delimiter, Spacing};
#[derive(Copy, Clone)]
pub struct Span {
lo: u32,
hi: u32,
}
impl Span {
pub fn call_site() -> Self {
Span { lo: 0, hi: 0 }
}
pub fn join(&self, other: Self) -> Option<Self> {
Some(Span {
lo: self.lo,
hi: other.hi,
})
}
}
#[derive(Clone)]
pub enum TokenTree {
Group(Group),
Ident(Ident),
Punct(Punct),
Literal(Literal),
}
impl TokenTree {
pub fn span(&self) -> Span {
match self {
TokenTree::Group(group) => group.span(),
TokenTree::Ident(ident) => ident.span(),
TokenTree::Punct(punct) => punct.span(),
TokenTree::Literal(literal) => literal.span(),
}
}
pub fn set_span(&mut self, span: Span) {
match self {
TokenTree::Group(group) => group.set_span(span),
TokenTree::Ident(ident) => ident.set_span(span),
TokenTree::Punct(punct) => punct.set_span(span),
TokenTree::Literal(literal) => literal.set_span(span),
}
}
}
impl From<Group> for TokenTree {
fn from(group: Group) -> Self {
TokenTree::Group(group)
}
}
impl From<Ident> for TokenTree {
fn from(ident: Ident) -> Self {
TokenTree::Ident(ident)
}
}
impl From<Punct> for TokenTree {
fn from(punct: Punct) -> Self {
TokenTree::Punct(punct)
}
}
impl From<Literal> for TokenTree {
fn from(literal: Literal) -> Self {
TokenTree::Literal(literal)
}
}
impl Debug for TokenTree {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
TokenTree::Group(group) => Debug::fmt(group, formatter),
TokenTree::Ident(ident) => {
let mut debug = formatter.debug_struct("Ident");
debug.field("sym", &format_args!("{}", ident));
debug.finish()
}
TokenTree::Punct(punct) => Debug::fmt(punct, formatter),
TokenTree::Literal(literal) => Debug::fmt(literal, formatter),
}
}
}
#[derive(Clone)]
pub struct Group {
delimiter: Delimiter,
stream: Vec<TokenTree>,
span: Span,
span_open: Span,
span_close: Span,
identity: u32,
}
impl Group {
pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self {
Group {
delimiter,
stream: stream.content,
span: Span::call_site(),
span_open: Span::call_site(),
span_close: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn stream(&self) -> TokenStream {
TokenStream {
content: self.stream.clone(),
}
}
pub fn delimiter(&self) -> Delimiter {
self.delimiter
}
pub fn span(&self) -> Span {
self.span
}
pub fn span_open(&self) -> Span {
self.span_open
}
pub fn span_close(&self) -> Span {
self.span_close
}
pub fn delim_span(&self) -> DelimSpan {
DelimSpan {
join: self.span,
open: self.span_open,
close: self.span_close,
}
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Group {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let (open, close) = match self.delimiter {
Delimiter::Parenthesis => ("(", ")"),
Delimiter::Brace => ("{ ", "}"),
Delimiter::Bracket => ("[", "]"),
Delimiter::None => ("", ""),
};
formatter.write_str(open)?;
display_tokens(&self.stream, formatter)?;
if self.delimiter == Delimiter::Brace && !self.stream.is_empty() {
formatter.write_str(" ")?;
}
formatter.write_str(close)?;
Ok(())
}
}
impl Debug for Group {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let mut debug = formatter.debug_struct("Group");
debug.field("delimiter", &self.delimiter);
debug.field("stream", &self.stream);
debug.finish()
}
}
#[derive(Clone)]
pub struct Ident {
fallback: proc_macro2::Ident,
span: Span,
identity: u32,
}
impl Ident {
pub fn new(string: &str, span: Span) -> Self {
Ident {
fallback: proc_macro2::Ident::new(string, proc_macro2::Span::call_site()),
span,
identity: Identity::NOVEL,
}
}
pub fn new_raw(string: &str, span: Span) -> Self {
Ident {
fallback: proc_macro2::Ident::new_raw(string, proc_macro2::Span::call_site()),
span,
identity: Identity::NOVEL,
}
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Ident {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Ident {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
impl Eq for Ident {}
impl PartialEq for Ident {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&self.fallback, &other.fallback)
}
}
impl<T> PartialEq<T> for Ident
where
T: ?Sized + AsRef<str>,
{
fn eq(&self, other: &T) -> bool {
PartialEq::eq(&self.fallback, other)
}
}
impl Ord for Ident {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&self.fallback, &other.fallback)
}
}
impl PartialOrd for Ident {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.fallback, &other.fallback)
}
}
impl Hash for Ident {
fn hash<H: Hasher>(&self, hasher: &mut H) {
Hash::hash(&self.fallback, hasher);
}
}
#[derive(Clone)]
pub struct Punct {
fallback: proc_macro2::Punct,
span: Span,
identity: u32,
}
impl Punct {
pub fn new(ch: char, spacing: Spacing) -> Self {
Punct {
fallback: proc_macro2::Punct::new(ch, spacing),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn as_char(&self) -> char {
self.fallback.as_char()
}
pub fn spacing(&self) -> Spacing {
self.fallback.spacing()
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Punct {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Punct {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
#[derive(Clone)]
pub struct Literal {
fallback: proc_macro2::Literal,
span: Span,
identity: u32,
}
impl Literal {
pub fn u8_suffixed(n: u8) -> Self {
Literal {
fallback: proc_macro2::Literal::u8_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u16_suffixed(n: u16) -> Self {
Literal {
fallback: proc_macro2::Literal::u16_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u32_suffixed(n: u32) -> Self {
Literal {
fallback: proc_macro2::Literal::u32_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u64_suffixed(n: u64) -> Self {
Literal {
fallback: proc_macro2::Literal::u64_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u128_suffixed(n: u128) -> Self {
Literal {
fallback: proc_macro2::Literal::u128_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn usize_suffixed(n: usize) -> Self {
Literal {
fallback: proc_macro2::Literal::usize_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i8_suffixed(n: i8) -> Self {
Literal {
fallback: proc_macro2::Literal::i8_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i16_suffixed(n: i16) -> Self {
Literal {
fallback: proc_macro2::Literal::i16_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i32_suffixed(n: i32) -> Self {
Literal {
fallback: proc_macro2::Literal::i32_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i64_suffixed(n: i64) -> Self {
Literal {
fallback: proc_macro2::Literal::i64_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i128_suffixed(n: i128) -> Self {
Literal {
fallback: proc_macro2::Literal::i128_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn isize_suffixed(n: isize) -> Self {
Literal {
fallback: proc_macro2::Literal::isize_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u8_unsuffixed(n: u8) -> Self {
Literal {
fallback: proc_macro2::Literal::u8_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u16_unsuffixed(n: u16) -> Self {
Literal {
fallback: proc_macro2::Literal::u16_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u32_unsuffixed(n: u32) -> Self {
Literal {
fallback: proc_macro2::Literal::u32_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u64_unsuffixed(n: u64) -> Self {
Literal {
fallback: proc_macro2::Literal::u64_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u128_unsuffixed(n: u128) -> Self {
Literal {
fallback: proc_macro2::Literal::u128_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn usize_unsuffixed(n: usize) -> Self {
Literal {
fallback: proc_macro2::Literal::usize_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i8_unsuffixed(n: i8) -> Self {
Literal {
fallback: proc_macro2::Literal::i8_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i16_unsuffixed(n: i16) -> Self {
Literal {
fallback: proc_macro2::Literal::i16_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i32_unsuffixed(n: i32) -> Self {
Literal {
fallback: proc_macro2::Literal::i32_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i64_unsuffixed(n: i64) -> Self {
Literal {
fallback: proc_macro2::Literal::i64_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i128_unsuffixed(n: i128) -> Self {
Literal {
fallback: proc_macro2::Literal::i128_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn isize_unsuffixed(n: isize) -> Self {
Literal {
fallback: proc_macro2::Literal::isize_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f64_unsuffixed(f: f64) -> Self {
Literal {
fallback: proc_macro2::Literal::f64_unsuffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f64_suffixed(f: f64) -> Self {
Literal {
fallback: proc_macro2::Literal::f64_suffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f32_unsuffixed(f: f32) -> Self {
Literal {
fallback: proc_macro2::Literal::f32_unsuffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f32_suffixed(f: f32) -> Self {
Literal {
fallback: proc_macro2::Literal::f32_suffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn string(string: &str) -> Self {
Literal {
fallback: proc_macro2::Literal::string(string),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn character(ch: char) -> Self {
Literal {
fallback: proc_macro2::Literal::character(ch),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn byte_string(s: &[u8]) -> Self {
Literal {
fallback: proc_macro2::Literal::byte_string(s),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
let _ = range;
None
}
}
impl FromStr for Literal {
type Err = LexError;
fn from_str(repr: &str) -> Result<Self, Self::Err> {
let fallback = match proc_macro2::Literal::from_str(repr) {
Ok(literal) => literal,
Err(error) => {
return Err(LexError {
fallback: error,
span: Span::call_site(),
});
}
};
Ok(Literal {
fallback,
span: Span::call_site(),
identity: Identity::NOVEL,
})
}
}
impl Display for Literal {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Literal {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
#[derive(Clone)]
pub struct TokenStream {
content: Vec<TokenTree>,
}
impl TokenStream {
pub fn new() -> Self {
TokenStream {
content: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
}
impl IntoIterator for TokenStream {
type Item = TokenTree;
type IntoIter = token_stream::IntoIter;
fn into_iter(self) -> Self::IntoIter {
token_stream::IntoIter {
iter: self.content.into_iter(),
}
}
}
impl Extend<TokenStream> for TokenStream {
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
self.content.extend(streams.into_iter().flatten());
}
}
impl Extend<TokenTree> for TokenStream {
fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
self.content.extend(streams);
}
}
impl FromIterator<TokenStream> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
let content = streams.into_iter().flatten().collect();
TokenStream { content }
}
}
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
let content = streams.into_iter().collect();
TokenStream { content }
}
}
impl FromStr for TokenStream {
type Err = LexError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let fallback = match proc_macro2::TokenStream::from_str(string) {
Ok(token_stream) => token_stream,
Err(error) => {
return Err(LexError {
fallback: error,
span: Span::call_site(),
});
}
};
fn convert_token_stream(stream: proc_macro2::TokenStream) -> TokenStream {
TokenStream {
content: stream.into_iter().map(convert_token_tree).collect(),
}
}
fn convert_token_tree(token: proc_macro2::TokenTree) -> TokenTree {
match token {
proc_macro2::TokenTree::Group(group) => TokenTree::Group(Group::new(
group.delimiter(),
convert_token_stream(group.stream()),
)),
proc_macro2::TokenTree::Ident(ident) => TokenTree::Ident(Ident {
fallback: ident,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
proc_macro2::TokenTree::Punct(punct) => TokenTree::Punct(Punct {
fallback: punct,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
proc_macro2::TokenTree::Literal(literal) => TokenTree::Literal(Literal {
fallback: literal,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
}
}
Ok(convert_token_stream(fallback))
}
}
fn display_tokens(tokens: &[TokenTree], formatter: &mut fmt::Formatter) -> fmt::Result {
let mut joint = false;
for (i, token) in tokens.iter().enumerate() {
if i != 0 && !joint {
write!(formatter, " ")?;
}
joint = false;
match token {
TokenTree::Group(group) => Display::fmt(group, formatter),
TokenTree::Ident(ident) => Display::fmt(ident, formatter),
TokenTree::Punct(punct) => {
joint = punct.spacing() == Spacing::Joint;
Display::fmt(punct, formatter)
}
TokenTree::Literal(literal) => Display::fmt(literal, formatter),
}?;
}
Ok(())
}
impl Display for TokenStream {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
display_tokens(&self.content, formatter)
}
}
impl Debug for TokenStream {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("TokenStream ")?;
formatter.debug_list().entries(&self.content).finish()
}
}
pub struct LexError {
fallback: proc_macro2::LexError,
span: Span,
}
impl LexError {
pub fn span(&self) -> Span {
self.span
}
}
impl Debug for LexError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
pub mod token_stream {
use super::*;
#[derive(Clone)]
pub struct IntoIter {
pub(crate) iter: <Vec<TokenTree> as IntoIterator>::IntoIter,
}
impl Iterator for IntoIter {
type Item = TokenTree;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
}
pub mod extra {
use crate::Span;
#[derive(Copy, Clone)]
pub struct DelimSpan {
pub(crate) join: Span,
pub(crate) open: Span,
pub(crate) close: Span,
}
impl DelimSpan {
pub fn join(&self) -> Span {
self.join
}
pub fn open(&self) -> Span {
self.open
}
pub fn close(&self) -> Span {
self.close
}
}
}
@@ -0,0 +1,69 @@
use std::str;
pub struct OutputBuffer {
bytes: Vec<u8>,
}
impl OutputBuffer {
pub fn new() -> Self {
OutputBuffer { bytes: Vec::new() }
}
pub fn write_u8(&mut self, value: u8) {
self.bytes.push(value);
}
pub fn write_u16(&mut self, value: u16) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn write_u32(&mut self, value: u32) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn write_str(&mut self, value: &str) {
self.bytes.extend_from_slice(value.as_bytes());
}
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}
pub struct InputBuffer<'a> {
bytes: &'a [u8],
}
impl<'a> InputBuffer<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
InputBuffer { bytes }
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub fn read_u8(&mut self) -> u8 {
let (first, rest) = self.bytes.split_first().unwrap();
self.bytes = rest;
*first
}
pub fn read_u16(&mut self) -> u16 {
let (value, rest) = self.bytes.split_at(2);
self.bytes = rest;
u16::from_le_bytes([value[0], value[1]])
}
pub fn read_u32(&mut self) -> u32 {
let (value, rest) = self.bytes.split_at(4);
self.bytes = rest;
u32::from_le_bytes([value[0], value[1], value[2], value[3]])
}
pub fn read_str(&mut self, len: usize) -> &'a str {
let (string, rest) = self.bytes.split_at(len);
self.bytes = rest;
str::from_utf8(string).unwrap()
}
}
@@ -0,0 +1,17 @@
pub enum Bytecode {}
impl Bytecode {
pub const GROUP_PARENTHESIS: u8 = 0;
pub const GROUP_BRACE: u8 = 1;
pub const GROUP_BRACKET: u8 = 2;
pub const GROUP_NONE: u8 = 3;
pub const IDENT: u8 = 4;
pub const PUNCT_ALONE: u8 = 5;
pub const PUNCT_JOINT: u8 = 6;
pub const LITERAL: u8 = 7;
pub const LOAD_GROUP: u8 = 8;
pub const LOAD_IDENT: u8 = 9;
pub const LOAD_PUNCT: u8 = 10;
pub const LOAD_LITERAL: u8 = 11;
pub const SET_SPAN: u8 = 12;
}
+205
View File
@@ -0,0 +1,205 @@
pub mod buffer;
pub mod bytecode;
use crate::watt::buffer::{InputBuffer, OutputBuffer};
use crate::watt::bytecode::Bytecode;
use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::str::FromStr;
pub enum Kind {
Group(Delimiter),
Ident,
Punct(Spacing),
Literal,
}
pub enum Identity {}
impl Identity {
pub const RESPANNED: u32 = 1 << 31;
pub const NOVEL: u32 = u32::MAX;
}
impl Span {
fn is_call_site(&self) -> bool {
self.lo == 0 && self.hi == 0
}
}
fn post_increment(counter: &mut u32) -> impl FnMut() -> u32 + '_ {
|| {
let value = *counter;
*counter += 1;
value
}
}
pub fn load(buf: &mut InputBuffer) -> TokenStream {
let mut span_counter = 1;
let mut next_span = post_increment(&mut span_counter);
let mut next_span = || {
let next = next_span();
Span { lo: next, hi: next }
};
let [mut group_counter, mut ident_counter, mut punct_counter, mut literal_counter] = [0; 4];
let mut next_group = post_increment(&mut group_counter);
let mut next_ident = post_increment(&mut ident_counter);
let mut next_punct = post_increment(&mut punct_counter);
let mut next_literal = post_increment(&mut literal_counter);
let mut trees = Vec::new();
while !buf.is_empty() {
match match buf.read_u8() {
Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
Bytecode::IDENT => Kind::Ident,
Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
Bytecode::LITERAL => Kind::Literal,
_ => unreachable!(),
} {
Kind::Group(delimiter) => {
let len = buf.read_u32();
let stream = trees.drain(trees.len() - len as usize..).collect();
trees.push(TokenTree::Group(Group {
delimiter,
stream,
span: next_span(),
span_open: next_span(),
span_close: next_span(),
identity: next_group(),
}));
}
Kind::Ident => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let ident = if let Some(repr) = repr.strip_prefix("r#") {
proc_macro2::Ident::new_raw(repr, proc_macro2::Span::call_site())
} else if repr == "$crate" {
proc_macro2::Ident::new("crate", proc_macro2::Span::call_site())
} else {
proc_macro2::Ident::new(repr, proc_macro2::Span::call_site())
};
trees.push(TokenTree::Ident(Ident {
fallback: ident,
span: next_span(),
identity: next_ident(),
}));
}
Kind::Punct(spacing) => {
let ch = buf.read_u8();
assert!(ch.is_ascii());
let punct = proc_macro2::Punct::new(ch as char, spacing);
trees.push(TokenTree::Punct(Punct {
fallback: punct,
span: next_span(),
identity: next_punct(),
}));
}
Kind::Literal => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let literal = proc_macro2::Literal::from_str(repr).unwrap();
trees.push(TokenTree::Literal(Literal {
fallback: literal,
span: next_span(),
identity: next_literal(),
}));
}
}
}
TokenStream { content: trees }
}
pub fn linearize(tokens: TokenStream) -> Vec<u8> {
let mut buf = OutputBuffer::new();
for token in &tokens.content {
linearize_token(token, &mut buf);
}
buf.into_bytes()
}
fn linearize_token(token: &TokenTree, buf: &mut OutputBuffer) {
let needs_span;
match token {
TokenTree::Group(group) => {
if group.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_GROUP);
buf.write_u32(group.identity & !Identity::RESPANNED);
needs_span = group.identity >= Identity::RESPANNED;
} else {
let len = group.stream.len();
assert!(len <= u32::MAX as usize);
for token in &group.stream {
linearize_token(token, buf);
}
buf.write_u8(match group.delimiter {
Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
Delimiter::Brace => Bytecode::GROUP_BRACE,
Delimiter::Bracket => Bytecode::GROUP_BRACKET,
Delimiter::None => Bytecode::GROUP_NONE,
});
buf.write_u32(len as u32);
needs_span = !group.span.is_call_site();
}
}
TokenTree::Ident(ident) => {
if ident.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_IDENT);
buf.write_u32(ident.identity & !Identity::RESPANNED);
needs_span = ident.identity >= Identity::RESPANNED;
} else {
buf.write_u8(Bytecode::IDENT);
let repr = ident.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
linearize_span(ident.span, buf);
needs_span = false;
}
}
TokenTree::Punct(punct) => {
if punct.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_PUNCT);
buf.write_u32(punct.identity & !Identity::RESPANNED);
needs_span = punct.identity >= Identity::RESPANNED;
} else {
buf.write_u8(match punct.spacing() {
Spacing::Alone => Bytecode::PUNCT_ALONE,
Spacing::Joint => Bytecode::PUNCT_JOINT,
});
let ch = punct.as_char();
assert!(ch.is_ascii());
buf.write_u8(ch as u8);
needs_span = !punct.span.is_call_site();
}
}
TokenTree::Literal(literal) => {
if literal.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_LITERAL);
buf.write_u32(literal.identity & !Identity::RESPANNED);
needs_span = literal.identity >= Identity::RESPANNED;
} else {
buf.write_u8(Bytecode::LITERAL);
let repr = literal.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
needs_span = !literal.span.is_call_site();
}
}
}
if needs_span {
buf.write_u8(Bytecode::SET_SPAN);
linearize_span(token.span(), buf);
}
}
fn linearize_span(span: Span, buf: &mut OutputBuffer) {
buf.write_u32(span.lo);
buf.write_u32(span.hi);
}
+36
View File
@@ -0,0 +1,36 @@
[package]
name = "serde_derive"
version = "1.0.174"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html"
edition = "2015"
homepage = "https://serde.rs"
include = ["serde_derive-x86_64-unknown-linux-gnu", "src"]
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"
[features]
default = []
deserialize_in_place = []
[lib]
proc-macro = true
[target.'cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))'.dependencies]
proc-macro2 = "1"
quote = "1"
syn = "2.0.25"
[dev-dependencies]
serde = { version = "1", path = "../../serde" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
[workspace]
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../../README.md
+1
View File
@@ -0,0 +1 @@
../../crates-io.md
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/bound.rs
+1
View File
@@ -0,0 +1 @@
../../proc-macro2/src/watt/buffer.rs
+1
View File
@@ -0,0 +1 @@
../../proc-macro2/src/watt/bytecode.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/de.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/dummy.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/fragment.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/internals/
+25
View File
@@ -0,0 +1,25 @@
//! This crate provides Serde's two derive macros.
//!
//! ```edition2021
//! # use serde_derive::{Deserialize, Serialize};
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.174")]
#![allow(unknown_lints, bare_trait_objects)]
extern crate proc_macro;
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
include!("lib_from_source.rs");
#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
include!("lib_precompiled.rs");
@@ -0,0 +1,39 @@
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro2;
mod internals;
use proc_macro::TokenStream;
use syn::DeriveInput;
#[macro_use]
mod bound;
#[macro_use]
mod fragment;
mod de;
mod dummy;
mod pretend;
mod ser;
mod this;
mod try;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
@@ -0,0 +1,219 @@
mod buffer;
mod bytecode;
use crate::buffer::{InputBuffer, OutputBuffer};
use crate::bytecode::Bytecode;
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::io::{Read, Write};
use std::iter::FromIterator;
use std::process::{Command, ExitStatus, Stdio};
use std::str::FromStr;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
derive(0, input)
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
derive(1 + cfg!(feature = "deserialize_in_place") as u8, input)
}
fn derive(select: u8, input: TokenStream) -> TokenStream {
let mut memory = TokenMemory::default();
let mut buf = OutputBuffer::new();
buf.write_u8(select);
memory.spans.push(Span::call_site());
for token in input {
memory.linearize_token(token, &mut buf);
}
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/serde_derive-x86_64-unknown-linux-gnu",
);
let mut child = Command::new(path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("failed to spawn process");
let mut stdin = child.stdin.take().unwrap();
let mut buf = buf.into_bytes();
stdin.write_all(&buf).unwrap();
drop(stdin);
let mut stdout = child.stdout.take().unwrap();
buf.clear();
stdout.read_to_end(&mut buf).unwrap();
let success = child.wait().as_ref().map_or(true, ExitStatus::success);
if !success || buf.is_empty() {
panic!();
}
let mut buf = InputBuffer::new(&buf);
memory.receive(&mut buf)
}
#[derive(Default)]
struct TokenMemory {
spans: Vec<Span>,
groups: Vec<Group>,
idents: Vec<Ident>,
puncts: Vec<Punct>,
literals: Vec<Literal>,
}
enum Kind {
Group(Delimiter),
Ident,
Punct(Spacing),
Literal,
}
impl TokenMemory {
// Depth-first post-order traversal.
fn linearize_token(&mut self, token: TokenTree, buf: &mut OutputBuffer) {
match token {
TokenTree::Group(group) => {
let mut len = 0usize;
for token in group.stream() {
self.linearize_token(token, buf);
len += 1;
}
assert!(len <= u32::MAX as usize);
buf.write_u8(match group.delimiter() {
Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
Delimiter::Brace => Bytecode::GROUP_BRACE,
Delimiter::Bracket => Bytecode::GROUP_BRACKET,
Delimiter::None => Bytecode::GROUP_NONE,
});
buf.write_u32(len as u32);
self.spans
.extend([group.span(), group.span_open(), group.span_close()]);
self.groups.push(group);
}
TokenTree::Ident(ident) => {
buf.write_u8(Bytecode::IDENT);
let repr = ident.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
self.spans.push(ident.span());
self.idents.push(ident);
}
TokenTree::Punct(punct) => {
buf.write_u8(match punct.spacing() {
Spacing::Alone => Bytecode::PUNCT_ALONE,
Spacing::Joint => Bytecode::PUNCT_JOINT,
});
let ch = punct.as_char();
assert!(ch.is_ascii());
buf.write_u8(ch as u8);
self.spans.push(punct.span());
self.puncts.push(punct);
}
TokenTree::Literal(literal) => {
buf.write_u8(Bytecode::LITERAL);
let repr = literal.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
self.spans.push(literal.span());
self.literals.push(literal);
}
}
}
fn receive(&self, buf: &mut InputBuffer) -> TokenStream {
let mut trees = Vec::new();
while !buf.is_empty() {
match match buf.read_u8() {
Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
Bytecode::IDENT => Kind::Ident,
Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
Bytecode::LITERAL => Kind::Literal,
Bytecode::LOAD_GROUP => {
let identity = buf.read_u32();
let group = self.groups[identity as usize].clone();
trees.push(TokenTree::Group(group));
continue;
}
Bytecode::LOAD_IDENT => {
let identity = buf.read_u32();
let ident = self.idents[identity as usize].clone();
trees.push(TokenTree::Ident(ident));
continue;
}
Bytecode::LOAD_PUNCT => {
let identity = buf.read_u32();
let punct = self.puncts[identity as usize].clone();
trees.push(TokenTree::Punct(punct));
continue;
}
Bytecode::LOAD_LITERAL => {
let identity = buf.read_u32();
let literal = self.literals[identity as usize].clone();
trees.push(TokenTree::Literal(literal));
continue;
}
Bytecode::SET_SPAN => {
trees.last_mut().unwrap().set_span(self.read_span(buf));
continue;
}
_ => unreachable!(),
} {
Kind::Group(delimiter) => {
let len = buf.read_u32();
let stream = trees.drain(trees.len() - len as usize..).collect();
let group = Group::new(delimiter, stream);
trees.push(TokenTree::Group(group));
}
Kind::Ident => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let span = self.read_span(buf);
let ident = if let Some(repr) = repr.strip_prefix("r#") {
Ident::new_raw(repr, span)
} else {
Ident::new(repr, span)
};
trees.push(TokenTree::Ident(ident));
}
Kind::Punct(spacing) => {
let ch = buf.read_u8();
assert!(ch.is_ascii());
let punct = Punct::new(ch as char, spacing);
trees.push(TokenTree::Punct(punct));
}
Kind::Literal => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let literal = Literal::from_str(repr).unwrap();
trees.push(TokenTree::Literal(literal));
}
}
}
TokenStream::from_iter(trees)
}
fn read_span(&self, buf: &mut InputBuffer) -> Span {
let lo = buf.read_u32();
let hi = buf.read_u32();
let span = self.spans[lo as usize];
if lo == hi {
span
} else {
#[cfg(any())] // FIXME
return span.join(self.spans[hi as usize]).unwrap_or(span);
span
}
}
}
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/pretend.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/ser.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/this.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/try.rs
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+6 -5
View File
@@ -1,13 +1,12 @@
[package]
name = "serde"
version = "1.0.155" # remember to update html_root_url and serde_derive dependency
version = "1.0.174" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std"]
categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "A generic serialization/deserialization framework"
documentation = "https://docs.rs/serde"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "no_std"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
@@ -15,10 +14,10 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde_derive = { version = "=1.0.155", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.174", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
serde_derive = { version = "1", path = "../serde_derive" }
[lib]
doc-scrape-examples = false
@@ -27,7 +26,9 @@ doc-scrape-examples = false
features = ["derive", "rc"]
[package.metadata.docs.rs]
features = ["derive"]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
### FEATURES #################################################################
+5 -5
View File
@@ -78,11 +78,6 @@ fn main() {
println!("cargo:rustc-cfg=no_num_nonzero");
}
// Current minimum supported version of serde_derive crate is Rust 1.31.
if minor < 31 {
println!("cargo:rustc-cfg=no_serde_derive");
}
// 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
@@ -94,6 +89,11 @@ fn main() {
println!("cargo:rustc-cfg=no_relaxed_trait_bounds");
}
// Current minimum supported version of serde_derive crate is Rust 1.56.
if minor < 56 {
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");
+4 -5
View File
@@ -10,13 +10,12 @@ use de::{
/// any type, except that it does not store any information about the data that
/// gets deserialized.
///
/// ```edition2018
/// use std::fmt;
/// use std::marker::PhantomData;
///
/// ```edition2021
/// use serde::de::{
/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor,
/// };
/// use std::fmt;
/// use std::marker::PhantomData;
///
/// /// A seed that can be used to deserialize only the `n`th element of a sequence
/// /// while efficiently discarding elements of any type before or after index `n`.
@@ -108,7 +107,7 @@ use de::{
/// # Ok(())
/// # }
/// ```
#[derive(Copy, Clone, Debug, Default)]
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct IgnoredAny;
impl<'de> Visitor<'de> for IgnoredAny {
+307 -30
View File
@@ -681,8 +681,8 @@ impl<'de> Visitor<'de> for CStringVisitor {
where
A: SeqAccess<'de>,
{
let len = size_hint::cautious(seq.size_hint());
let mut values = Vec::with_capacity(len);
let capacity = size_hint::cautious::<u8>(seq.size_hint());
let mut values = Vec::<u8>::with_capacity(capacity);
while let Some(value) = try!(seq.next_element()) {
values.push(value);
@@ -747,7 +747,10 @@ macro_rules! forwarded_impl {
}
}
#[cfg(all(any(feature = "std", all(not(no_core_cstr), feature = "alloc")), not(no_de_boxed_c_str)))]
#[cfg(all(
any(feature = "std", all(not(no_core_cstr), feature = "alloc")),
not(no_de_boxed_c_str)
))]
forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str);
#[cfg(not(no_core_reverse))]
@@ -933,7 +936,7 @@ macro_rules! seq_impl {
A: SeqAccess<'de>,
{
$clear(&mut self.0);
$reserve(&mut self.0, size_hint::cautious($access.size_hint()));
$reserve(&mut self.0, size_hint::cautious::<T>($access.size_hint()));
// FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList)
while let Some(value) = try!($access.next_element()) {
@@ -959,7 +962,7 @@ seq_impl!(
BinaryHeap<T: Ord>,
seq,
BinaryHeap::clear,
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::with_capacity(size_hint::cautious::<T>(seq.size_hint())),
BinaryHeap::reserve,
BinaryHeap::push
);
@@ -989,16 +992,17 @@ seq_impl!(
HashSet<T: Eq + Hash, S: BuildHasher + Default>,
seq,
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::with_capacity_and_hasher(size_hint::cautious::<T>(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert);
HashSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
VecDeque<T>,
seq,
VecDeque::clear,
VecDeque::with_capacity(size_hint::cautious(seq.size_hint())),
VecDeque::with_capacity(size_hint::cautious::<T>(seq.size_hint())),
VecDeque::reserve,
VecDeque::push_back
);
@@ -1032,7 +1036,8 @@ where
where
A: SeqAccess<'de>,
{
let mut values = Vec::with_capacity(size_hint::cautious(seq.size_hint()));
let capacity = size_hint::cautious::<T>(seq.size_hint());
let mut values = Vec::<T>::with_capacity(capacity);
while let Some(value) = try!(seq.next_element()) {
values.push(value);
@@ -1068,7 +1073,7 @@ where
where
A: SeqAccess<'de>,
{
let hint = size_hint::cautious(seq.size_hint());
let hint = size_hint::cautious::<T>(seq.size_hint());
if let Some(additional) = hint.checked_sub(self.0.len()) {
self.0.reserve(additional);
}
@@ -1406,16 +1411,14 @@ macro_rules! map_impl {
}
#[cfg(any(feature = "std", feature = "alloc"))]
map_impl!(
BTreeMap<K: Ord, V>,
map,
BTreeMap::new());
map_impl!(BTreeMap<K: Ord, V>, map, BTreeMap::new());
#[cfg(feature = "std")]
map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map,
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default()));
HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default())
);
////////////////////////////////////////////////////////////////////////////////
@@ -1448,7 +1451,7 @@ macro_rules! variant_identifier {
$($variant),*
}
static $variants_name: &'static [&'static str] = &[$(stringify!($variant)),*];
static $variants_name: &[&str] = &[$(stringify!($variant)),*];
impl<'de> Deserialize<'de> for $name_kind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -1585,7 +1588,7 @@ macro_rules! parse_socket_impl {
if deserializer.is_human_readable() {
deserializer.deserialize_str(FromStrVisitor::new($expecting))
} else {
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
<(_, u16)>::deserialize(deserializer).map($new)
}
}
}
@@ -1612,12 +1615,10 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
}
#[cfg(feature = "std")]
parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, net::SocketAddrV4::new);
parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, |(ip, port)| net::SocketAddrV4::new(ip, port));
#[cfg(feature = "std")]
parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
ip, port, 0, 0
));
parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0));
////////////////////////////////////////////////////////////////////////////////
@@ -2096,7 +2097,7 @@ impl<'de> Deserialize<'de> for Duration {
}
}
const FIELDS: &'static [&'static str] = &["secs", "nanos"];
const FIELDS: &[&str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}
@@ -2238,7 +2239,7 @@ impl<'de> Deserialize<'de> for SystemTime {
}
}
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"];
const FIELDS: &[&str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
#[cfg(not(no_systemtime_checked_add))]
let ret = UNIX_EPOCH
@@ -2256,9 +2257,9 @@ impl<'de> Deserialize<'de> for SystemTime {
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct Range {
// start: u64,
// end: u32,
// struct Range<Idx> {
// start: Idx,
// end: Idx,
// }
impl<'de, Idx> Deserialize<'de> for Range<Idx>
where
@@ -2306,7 +2307,7 @@ mod range {
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &'static [&'static str] = &["start", "end"];
pub const FIELDS: &[&str] = &["start", "end"];
// If this were outside of the serde crate, it would just use:
//
@@ -2432,6 +2433,282 @@ mod range {
////////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct RangeFrom<Idx> {
// start: Idx,
// }
impl<'de, Idx> Deserialize<'de> for RangeFrom<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let start = try!(deserializer.deserialize_struct(
"RangeFrom",
range_from::FIELDS,
range_from::RangeFromVisitor {
expecting: "struct RangeFrom",
phantom: PhantomData,
},
));
Ok(start..)
}
}
mod range_from {
use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &[&str] = &["end"];
// If this were outside of the serde crate, it would just use:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
enum Field {
End,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`end`")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"end" => Ok(Field::End),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
b"end" => Ok(Field::End),
_ => {
let value = ::__private::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
pub struct RangeFromVisitor<Idx> {
pub expecting: &'static str,
pub phantom: PhantomData<Idx>,
}
impl<'de, Idx> Visitor<'de> for RangeFromVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = Idx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expecting)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let end: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
Ok(end)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut end: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::End => {
if end.is_some() {
return Err(<A::Error as Error>::duplicate_field("end"));
}
end = Some(try!(map.next_value()));
}
}
}
let end = match end {
Some(end) => end,
None => return Err(<A::Error as Error>::missing_field("end")),
};
Ok(end)
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct RangeTo<Idx> {
// start: Idx,
// }
impl<'de, Idx> Deserialize<'de> for RangeTo<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let end = try!(deserializer.deserialize_struct(
"RangeTo",
range_to::FIELDS,
range_to::RangeToVisitor {
expecting: "struct RangeTo",
phantom: PhantomData,
},
));
Ok(..end)
}
}
mod range_to {
use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &[&str] = &["start"];
// If this were outside of the serde crate, it would just use:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Start,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`start`")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"start" => Ok(Field::Start),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
b"start" => Ok(Field::Start),
_ => {
let value = ::__private::from_utf8_lossy(value);
Err(Error::unknown_field(&*value, FIELDS))
}
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
pub struct RangeToVisitor<Idx> {
pub expecting: &'static str,
pub phantom: PhantomData<Idx>,
}
impl<'de, Idx> Visitor<'de> for RangeToVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = Idx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expecting)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let start: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
Ok(start)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut start: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::Start => {
if start.is_some() {
return Err(<A::Error as Error>::duplicate_field("start"));
}
start = Some(try!(map.next_value()));
}
}
}
let start = match start {
Some(start) => start,
None => return Err(<A::Error as Error>::missing_field("start")),
};
Ok(start)
}
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))]
impl<'de, T> Deserialize<'de> for Bound<T>
where
@@ -2532,7 +2809,7 @@ where
}
}
const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"];
const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"];
deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData))
}
@@ -2640,7 +2917,7 @@ where
}
}
const VARIANTS: &'static [&'static str] = &["Ok", "Err"];
const VARIANTS: &[&str] = &["Ok", "Err"];
deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData))
}
@@ -2706,7 +2983,7 @@ struct FromStrVisitor<T> {
impl<T> FromStrVisitor<T> {
fn new(expecting: &'static str) -> Self {
FromStrVisitor {
expecting: expecting,
expecting,
ty: PhantomData,
}
}
+27 -31
View File
@@ -162,7 +162,7 @@ macro_rules! declare_error_trait {
///
/// The message should not be capitalized and should not end with a period.
///
/// ```edition2018
/// ```edition2021
/// # use std::str::FromStr;
/// #
/// # struct IpAddr;
@@ -307,7 +307,7 @@ declare_error_trait!(Error: Sized + Debug + Display);
/// This is used as an argument to the `invalid_type`, `invalid_value`, and
/// `invalid_length` methods of the `Error` trait to build error messages.
///
/// ```edition2018
/// ```edition2021
/// # use std::fmt;
/// #
/// # use serde::de::{self, Unexpected, Visitor};
@@ -432,10 +432,9 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// Within the context of a `Visitor` implementation, the `Visitor` itself
/// (`&self`) is an implementation of this trait.
///
/// ```edition2018
/// # use std::fmt;
/// #
/// ```edition2021
/// # use serde::de::{self, Unexpected, Visitor};
/// # use std::fmt;
/// #
/// # struct Example;
/// #
@@ -457,7 +456,7 @@ impl<'a> fmt::Display for Unexpected<'a> {
///
/// Outside of a `Visitor`, `&"..."` can be used.
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{self, Unexpected};
/// #
/// # fn example<E>() -> Result<(), E>
@@ -465,7 +464,10 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// # E: de::Error,
/// # {
/// # let v = true;
/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer"));
/// return Err(de::Error::invalid_type(
/// Unexpected::Bool(v),
/// &"a negative integer",
/// ));
/// # }
/// ```
pub trait Expected {
@@ -577,7 +579,7 @@ pub trait Deserialize<'de>: Sized {
/// from the input string, but a `from_reader` function may only deserialize
/// owned data.
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{Deserialize, DeserializeOwned};
/// # use std::io::{Read, Result};
/// #
@@ -616,7 +618,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
///
/// The canonical API for stateless deserialization looks like this:
///
/// ```edition2018
/// ```edition2021
/// # use serde::Deserialize;
/// #
/// # enum Error {}
@@ -630,7 +632,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// Adjusting an API like this to support stateful deserialization is a matter
/// of accepting a seed as input:
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::DeserializeSeed;
/// #
/// # enum Error {}
@@ -663,12 +665,11 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// into it. This requires stateful deserialization using the `DeserializeSeed`
/// trait.
///
/// ```edition2018
/// ```edition2021
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
/// use std::fmt;
/// use std::marker::PhantomData;
///
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
///
/// // A DeserializeSeed implementation that uses stateful deserialization to
/// // append array elements onto the end of an existing vector. The preexisting
/// // state ("seed") in this case is the Vec<T>. The `deserialize` method of
@@ -709,7 +710,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// {
/// // Decrease the number of reallocations if there are many elements
/// if let Some(size_hint) = seq.size_hint() {
/// self.0.reserve(size_hint);
/// self.0.reserve(size_hint);
/// }
///
/// // Visit each element in the inner array and push it onto
@@ -1158,7 +1159,7 @@ pub trait Deserializer<'de>: Sized {
/// human-readable one and binary formats like Postcard will prefer the
/// compact one.
///
/// ```edition2018
/// ```edition2021
/// # use std::ops::Add;
/// # use std::str::FromStr;
/// #
@@ -1249,10 +1250,9 @@ pub trait Deserializer<'de>: Sized {
///
/// # Example
///
/// ```edition2018
/// # use std::fmt;
/// #
/// ```edition2021
/// # use serde::de::{self, Unexpected, Visitor};
/// # use std::fmt;
/// #
/// /// A visitor that deserializes a long string - a string containing at least
/// /// some minimum number of bytes.
@@ -1290,7 +1290,7 @@ pub trait Visitor<'de>: Sized {
/// "an integer between 0 and 64". The message should not be capitalized and
/// should not end with a period.
///
/// ```edition2018
/// ```edition2021
/// # use std::fmt;
/// #
/// # struct S {
@@ -2035,7 +2035,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed:
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// #
/// # struct X;
@@ -2075,7 +2075,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed:
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// #
/// # struct X;
@@ -2131,7 +2131,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed:
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// #
/// # struct X;
@@ -2148,11 +2148,7 @@ pub trait VariantAccess<'de>: Sized {
/// # T: DeserializeSeed<'de>,
/// # { unimplemented!() }
/// #
/// fn tuple_variant<V>(
/// self,
/// _len: usize,
/// _visitor: V,
/// ) -> Result<V::Value, Self::Error>
/// fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
/// where
/// V: Visitor<'de>,
/// {
@@ -2178,7 +2174,7 @@ pub trait VariantAccess<'de>: Sized {
/// If the data contains a different type of variant, the following
/// `invalid_type` error should be constructed:
///
/// ```edition2018
/// ```edition2021
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
/// #
/// # struct X;
@@ -2238,10 +2234,10 @@ pub trait VariantAccess<'de>: Sized {
///
/// # Example
///
/// ```edition2018
/// ```edition2021
/// use serde::de::{value, Deserialize, IntoDeserializer};
/// use serde_derive::Deserialize;
/// use std::str::FromStr;
/// use serde::Deserialize;
/// use serde::de::{value, IntoDeserializer};
///
/// #[derive(Deserialize)]
/// enum Setting {
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn encode(c: char) -> Encode {
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
0
};
Encode { buf: buf, pos: pos }
Encode { buf, pos }
}
pub struct Encode {
+17 -21
View File
@@ -1,10 +1,10 @@
//! Building blocks for deserializing basic values using the `IntoDeserializer`
//! trait.
//!
//! ```edition2018
//! ```edition2021
//! use serde::de::{value, Deserialize, IntoDeserializer};
//! use serde_derive::Deserialize;
//! use std::str::FromStr;
//! use serde::Deserialize;
//! use serde::de::{value, IntoDeserializer};
//!
//! #[derive(Deserialize)]
//! enum Setting {
@@ -251,7 +251,7 @@ macro_rules! primitive_deserializer {
#[allow(missing_docs)]
pub fn new(value: $ty) -> Self {
$name {
value: value,
value,
marker: PhantomData,
}
}
@@ -330,7 +330,7 @@ impl<E> U32Deserializer<E> {
#[allow(missing_docs)]
pub fn new(value: u32) -> Self {
U32Deserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -419,7 +419,7 @@ impl<'a, E> StrDeserializer<'a, E> {
#[allow(missing_docs)]
pub fn new(value: &'a str) -> Self {
StrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -498,7 +498,7 @@ impl<'de, E> BorrowedStrDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given string.
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
BorrowedStrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -598,7 +598,7 @@ impl<E> StringDeserializer<E> {
#[allow(missing_docs)]
pub fn new(value: String) -> Self {
StringDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -701,7 +701,7 @@ impl<'a, E> CowStrDeserializer<'a, E> {
#[allow(missing_docs)]
pub fn new(value: Cow<'a, str>) -> Self {
CowStrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -783,7 +783,7 @@ impl<'a, E> BytesDeserializer<'a, E> {
/// Create a new deserializer from the given bytes.
pub fn new(value: &'a [u8]) -> Self {
BytesDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -842,7 +842,7 @@ impl<'de, E> BorrowedBytesDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given borrowed bytes.
pub fn new(value: &'de [u8]) -> Self {
BorrowedBytesDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -1053,7 +1053,7 @@ pub struct SeqAccessDeserializer<A> {
impl<A> SeqAccessDeserializer<A> {
/// Construct a new `SeqAccessDeserializer<A>`.
pub fn new(seq: A) -> Self {
SeqAccessDeserializer { seq: seq }
SeqAccessDeserializer { seq }
}
}
@@ -1454,7 +1454,7 @@ pub struct MapAccessDeserializer<A> {
impl<A> MapAccessDeserializer<A> {
/// Construct a new `MapAccessDeserializer<A>`.
pub fn new(map: A) -> Self {
MapAccessDeserializer { map: map }
MapAccessDeserializer { map }
}
}
@@ -1519,7 +1519,7 @@ pub struct EnumAccessDeserializer<A> {
impl<A> EnumAccessDeserializer<A> {
/// Construct a new `EnumAccessDeserializer<A>`.
pub fn new(access: A) -> Self {
EnumAccessDeserializer { access: access }
EnumAccessDeserializer { access }
}
}
@@ -1613,7 +1613,7 @@ mod private {
}
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
MapAsEnum { map: map }
MapAsEnum { map }
}
impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
@@ -1637,10 +1637,7 @@ mod private {
where
V: Visitor<'de>,
{
self.map.next_value_seed(SeedTupleVariant {
len: len,
visitor: visitor,
})
self.map.next_value_seed(SeedTupleVariant { len, visitor })
}
fn struct_variant<V>(
@@ -1651,8 +1648,7 @@ mod private {
where
V: Visitor<'de>,
{
self.map
.next_value_seed(SeedStructVariant { visitor: visitor })
self.map.next_value_seed(SeedStructVariant { visitor })
}
}
+3 -3
View File
@@ -9,7 +9,7 @@
/// or do not target platforms that lack 128-bit integers, do not need to
/// bother with this macro and may assume support for 128-bit integers.
///
/// ```edition2018
/// ```edition2021
/// # use serde::__private::doc::Error;
/// #
/// # struct MySerializer;
@@ -50,7 +50,7 @@
/// When Serde is built with support for 128-bit integers, this macro expands
/// transparently into just the input tokens.
///
/// ```edition2018
/// ```edition2021
/// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => {
/// $($tt)*
@@ -61,7 +61,7 @@
/// When built without support for 128-bit integers, this macro expands to
/// nothing.
///
/// ```edition2018
/// ```edition2021
/// macro_rules! serde_if_integer128 {
/// ($($tt:tt)*) => {};
/// }
+6 -5
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.155")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.174")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
@@ -180,7 +180,7 @@ mod lib {
pub use self::core::fmt::{self, Debug, Display};
pub use self::core::marker::{self, PhantomData};
pub use self::core::num::Wrapping;
pub use self::core::ops::Range;
pub use self::core::ops::{Range, RangeFrom, RangeTo};
pub use self::core::option::{self, Option};
pub use self::core::result::{self, Result};
@@ -225,7 +225,7 @@ mod lib {
pub use std::ffi::CStr;
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
pub use alloc::ffi::{CString};
pub use alloc::ffi::CString;
#[cfg(feature = "std")]
pub use std::ffi::CString;
@@ -338,9 +338,10 @@ mod std_error;
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
/// Derive macro available if serde is built with `features = ["derive"]`.
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
pub use serde_derive::{Deserialize, Serialize};
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
mod actually_private {
+4 -5
View File
@@ -11,7 +11,7 @@
/// input. This requires repetitive implementations of all the [`Deserializer`]
/// trait methods.
///
/// ```edition2018
/// ```edition2021
/// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor};
/// #
@@ -47,7 +47,7 @@
/// methods so that they forward directly to [`Deserializer::deserialize_any`].
/// You can choose which methods to forward.
///
/// ```edition2018
/// ```edition2021
/// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor};
/// #
@@ -78,11 +78,10 @@
/// called `V`. A different type parameter and a different lifetime can be
/// specified explicitly if necessary.
///
/// ```edition2018
/// # use std::marker::PhantomData;
/// #
/// ```edition2021
/// # use serde::forward_to_deserialize_any;
/// # use serde::de::{value, Deserializer, Visitor};
/// # use std::marker::PhantomData;
/// #
/// # struct MyDeserializer<V>(PhantomData<V>);
/// #
+132 -151
View File
@@ -474,7 +474,8 @@ mod content {
where
V: SeqAccess<'de>,
{
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
let mut vec =
Vec::<Content>::with_capacity(size_hint::cautious::<Content>(visitor.size_hint()));
while let Some(e) = try!(visitor.next_element()) {
vec.push(e);
}
@@ -485,7 +486,10 @@ mod content {
where
V: MapAccess<'de>,
{
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
let mut vec =
Vec::<(Content, Content)>::with_capacity(
size_hint::cautious::<(Content, Content)>(visitor.size_hint()),
);
while let Some(kv) = try!(visitor.next_entry()) {
vec.push(kv);
}
@@ -518,7 +522,7 @@ mod content {
impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self {
TagOrContentVisitor {
name: name,
name,
value: PhantomData,
}
}
@@ -797,51 +801,29 @@ mod content {
/// Used by generated code to deserialize an internally tagged enum.
///
/// Not public API.
pub struct TaggedContent<'de, T> {
pub tag: T,
pub content: Content<'de>,
}
/// Not public API.
pub struct TaggedContentVisitor<'de, T> {
pub struct TaggedContentVisitor<T> {
tag_name: &'static str,
expecting: &'static str,
value: PhantomData<TaggedContent<'de, T>>,
value: PhantomData<T>,
}
impl<'de, T> TaggedContentVisitor<'de, T> {
impl<T> TaggedContentVisitor<T> {
/// Visitor for the content of an internally tagged enum with the given
/// tag name.
pub fn new(name: &'static str, expecting: &'static str) -> Self {
TaggedContentVisitor {
tag_name: name,
expecting: expecting,
expecting,
value: PhantomData,
}
}
}
impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<'de, T>
impl<'de, T> Visitor<'de> for TaggedContentVisitor<T>
where
T: Deserialize<'de>,
{
type Value = TaggedContent<'de, T>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
// Internally tagged enums are only supported in self-describing
// formats.
deserializer.deserialize_any(self)
}
}
impl<'de, T> Visitor<'de> for TaggedContentVisitor<'de, T>
where
T: Deserialize<'de>,
{
type Value = TaggedContent<'de, T>;
type Value = (T, Content<'de>);
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.expecting)
@@ -858,10 +840,7 @@ mod content {
}
};
let rest = de::value::SeqAccessDeserializer::new(seq);
Ok(TaggedContent {
tag: tag,
content: try!(Content::deserialize(rest)),
})
Ok((tag, try!(Content::deserialize(rest))))
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
@@ -869,7 +848,10 @@ mod content {
M: MapAccess<'de>,
{
let mut tag = None;
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
let mut vec = Vec::<(Content, Content)>::with_capacity(size_hint::cautious::<(
Content,
Content,
)>(map.size_hint()));
while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k {
TagOrContent::Tag => {
@@ -886,10 +868,7 @@ mod content {
}
match tag {
None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => Ok(TaggedContent {
tag: tag,
content: Content::Map(vec),
}),
Some(tag) => Ok((tag, Content::Map(vec))),
}
}
}
@@ -915,7 +894,7 @@ mod content {
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(self)
deserializer.deserialize_identifier(self)
}
}
@@ -926,6 +905,20 @@ mod content {
write!(formatter, "{:?} or {:?}", self.tag, self.content)
}
fn visit_u64<E>(self, field_index: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
match field_index {
0 => Ok(TagOrContentField::Tag),
1 => Ok(TagOrContentField::Content),
_ => Err(de::Error::invalid_value(
Unexpected::Unsigned(field_index),
&self,
)),
}
}
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
where
E: de::Error,
@@ -938,6 +931,19 @@ mod content {
Err(de::Error::invalid_value(Unexpected::Str(field), &self))
}
}
fn visit_bytes<E>(self, field: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag.as_bytes() {
Ok(TagOrContentField::Tag)
} else if field == self.content.as_bytes() {
Ok(TagOrContentField::Content)
} else {
Err(de::Error::invalid_value(Unexpected::Bytes(field), &self))
}
}
}
/// Used by generated code to deserialize an adjacently tagged enum when
@@ -963,7 +969,7 @@ mod content {
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(self)
deserializer.deserialize_identifier(self)
}
}
@@ -978,13 +984,31 @@ mod content {
)
}
fn visit_u64<E>(self, field_index: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
match field_index {
0 => Ok(TagContentOtherField::Tag),
1 => Ok(TagContentOtherField::Content),
_ => Ok(TagContentOtherField::Other),
}
}
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag {
self.visit_bytes(field.as_bytes())
}
fn visit_bytes<E>(self, field: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag.as_bytes() {
Ok(TagContentOtherField::Tag)
} else if field == self.content {
} else if field == self.content.as_bytes() {
Ok(TagContentOtherField::Content)
} else {
Ok(TagContentOtherField::Other)
@@ -1457,7 +1481,7 @@ mod content {
/// private API, don't use
pub fn new(content: Content<'de>) -> Self {
ContentDeserializer {
content: content,
content,
err: PhantomData,
}
}
@@ -1478,8 +1502,8 @@ mod content {
{
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
EnumDeserializer {
variant: variant,
value: value,
variant,
value,
err: PhantomData,
}
}
@@ -2135,8 +2159,8 @@ mod content {
};
visitor.visit_enum(EnumRefDeserializer {
variant: variant,
value: value,
variant,
value,
err: PhantomData,
})
}
@@ -2180,12 +2204,20 @@ mod content {
/// private API, don't use
pub fn new(content: &'a Content<'de>) -> Self {
ContentRefDeserializer {
content: content,
content,
err: PhantomData,
}
}
}
impl<'a, 'de: 'a, E> Copy for ContentRefDeserializer<'a, 'de, E> {}
impl<'a, 'de: 'a, E> Clone for ContentRefDeserializer<'a, 'de, E> {
fn clone(&self) -> Self {
*self
}
}
struct EnumRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
@@ -2481,8 +2513,8 @@ mod content {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
InternallyTaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
type_name,
variant_name,
}
}
}
@@ -2526,8 +2558,8 @@ mod content {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
UntaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
type_name,
variant_name,
}
}
}
@@ -2731,11 +2763,7 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
self.deserialize_map(visitor)
}
fn deserialize_enum<V>(
@@ -2747,17 +2775,8 @@ where
where
V: Visitor<'de>,
{
for item in self.0.iter_mut() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
};
if use_item {
let (key, value) = item.take().unwrap();
for entry in self.0 {
if let Some((key, value)) = flat_map_take_entry(entry, variants) {
return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
}
}
@@ -2772,7 +2791,11 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatMapAccess::new(self.0.iter()))
visitor.visit_map(FlatMapAccess {
iter: self.0.iter(),
pending_content: None,
_marker: PhantomData,
})
}
fn deserialize_struct<V>(
@@ -2784,7 +2807,12 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields))
visitor.visit_map(FlatStructAccess {
iter: self.0.iter_mut(),
pending_content: None,
fields,
_marker: PhantomData,
})
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
@@ -2811,6 +2839,13 @@ where
visitor.visit_unit()
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
forward_to_deserialize_other! {
deserialize_bool()
deserialize_i8()
@@ -2833,30 +2868,16 @@ where
deserialize_tuple(usize)
deserialize_tuple_struct(&'static str, usize)
deserialize_identifier()
deserialize_ignored_any()
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> {
struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where
@@ -2871,6 +2892,10 @@ where
for item in &mut self.iter {
// Items in the vector are nulled out when used by a struct.
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending_content = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
@@ -2890,28 +2915,13 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatStructAccess<'a, 'de: 'a, E> {
struct FlatStructAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>,
fields: &'static [&'static str],
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: &'static [&'static str],
) -> FlatStructAccess<'a, 'de, E> {
FlatStructAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
where
@@ -2923,17 +2933,8 @@ where
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)),
};
if use_item {
let (key, content) = item.take().unwrap();
for entry in self.iter.by_ref() {
if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some);
}
@@ -2952,44 +2953,24 @@ where
}
}
/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the
/// field name matches any of the recognized ones.
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
fn flat_map_take_entry<'de>(
entry: &mut Option<(Content<'de>, Content<'de>)>,
recognized: &[&str],
) -> Option<(Content<'de>, Content<'de>)> {
// Entries in the FlatMapDeserializer buffer are nulled out as they get
// claimed for deserialization. We only use an entry if it is still present
// and if the field is one recognized by the current data structure.
let is_recognized = match entry {
None => false,
Some((k, _v)) => k.as_str().map_or(false, |name| recognized.contains(&name)),
};
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E>
where
E: Error,
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
for item in &mut self.iter {
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
if is_recognized {
entry.take()
} else {
None
}
}
+18 -18
View File
@@ -27,10 +27,10 @@ where
T: Serialize,
{
value.serialize(TaggedSerializer {
type_ident: type_ident,
variant_ident: variant_ident,
tag: tag,
variant_name: variant_name,
type_ident,
variant_ident,
tag,
variant_name,
delegate: serializer,
})
}
@@ -350,8 +350,8 @@ mod content {
impl<M> SerializeTupleVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeTupleVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::with_capacity(len),
}
}
@@ -390,8 +390,8 @@ mod content {
impl<M> SerializeStructVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeStructVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::with_capacity(len),
}
}
@@ -711,7 +711,7 @@ mod content {
len: usize,
) -> Result<Self::SerializeTupleStruct, E> {
Ok(SerializeTupleStruct {
name: name,
name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -725,9 +725,9 @@ mod content {
len: usize,
) -> Result<Self::SerializeTupleVariant, E> {
Ok(SerializeTupleVariant {
name: name,
variant_index: variant_index,
variant: variant,
name,
variant_index,
variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -747,7 +747,7 @@ mod content {
len: usize,
) -> Result<Self::SerializeStruct, E> {
Ok(SerializeStruct {
name: name,
name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -761,9 +761,9 @@ mod content {
len: usize,
) -> Result<Self::SerializeStructVariant, E> {
Ok(SerializeStructVariant {
name: name,
variant_index: variant_index,
variant: variant,
name,
variant_index,
variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -1273,8 +1273,8 @@ where
{
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::new(),
}
}
+11 -3
View File
@@ -8,9 +8,17 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
pub fn cautious<Element>(hint: Option<usize>) -> usize {
const MAX_PREALLOC_BYTES: usize = 1024 * 1024;
if mem::size_of::<Element>() == 0 {
0
} else {
cmp::min(
hint.unwrap_or(0),
MAX_PREALLOC_BYTES / mem::size_of::<Element>(),
)
}
}
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
+3 -2
View File
@@ -17,8 +17,9 @@ macro_rules! fmt_primitives {
};
}
/// ```edition2018
/// use serde::Serialize;
/// ```edition2021
/// use serde::ser::Serialize;
/// use serde_derive::Serialize;
/// use std::fmt::{self, Display};
///
/// #[derive(Serialize)]
+35 -1
View File
@@ -257,6 +257,23 @@ where
////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeFrom<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeFrom", 1));
try!(state.serialize_field("start", &self.start));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(not(no_range_inclusive))]
impl<Idx> Serialize for RangeInclusive<Idx>
where
@@ -276,6 +293,23 @@ where
////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeTo<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeTo", 1));
try!(state.serialize_field("end", &self.end));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))]
impl<T> Serialize for Bound<T>
where
@@ -713,7 +747,7 @@ impl Serialize for net::IpAddr {
}
#[cfg(feature = "std")]
const DEC_DIGITS_LUT: &'static [u8] = b"\
const DEC_DIGITS_LUT: &[u8] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
+1 -1
View File
@@ -15,7 +15,7 @@ use ser::{
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
///
/// ```edition2018
/// ```edition2021
/// # use serde::ser::{Serializer, Impossible};
/// # use serde::__private::doc::Error;
/// #
+60 -64
View File
@@ -149,7 +149,7 @@ macro_rules! declare_error_trait {
/// For example, a filesystem [`Path`] may refuse to serialize
/// itself if it contains invalid UTF-8 data.
///
/// ```edition2018
/// ```edition2021
/// # struct Path;
/// #
/// # impl Path {
@@ -221,7 +221,7 @@ pub trait Serialize {
/// See the [Implementing `Serialize`] section of the manual for more
/// information about how to implement this method.
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer};
///
/// struct Person {
@@ -388,7 +388,7 @@ pub trait Serializer: Sized {
/// Serialize a `bool` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -410,7 +410,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -432,7 +432,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -454,7 +454,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `i64` and
/// forward to `serialize_i64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -472,7 +472,7 @@ pub trait Serializer: Sized {
/// Serialize an `i64` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -491,7 +491,7 @@ pub trait Serializer: Sized {
serde_if_integer128! {
/// Serialize an `i128` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -520,7 +520,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -542,7 +542,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -564,7 +564,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `u64` and
/// forward to `serialize_u64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -582,7 +582,7 @@ pub trait Serializer: Sized {
/// Serialize a `u64` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -601,7 +601,7 @@ pub trait Serializer: Sized {
serde_if_integer128! {
/// Serialize a `u128` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -630,7 +630,7 @@ pub trait Serializer: Sized {
/// reasonable implementation would be to cast the value to `f64` and
/// forward to `serialize_f64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -648,7 +648,7 @@ pub trait Serializer: Sized {
/// Serialize an `f64` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -669,7 +669,7 @@ pub trait Serializer: Sized {
/// If the format does not support characters, it is reasonable to serialize
/// it as a single element `str` or a `u32`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -687,7 +687,7 @@ pub trait Serializer: Sized {
/// Serialize a `&str`.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -711,7 +711,7 @@ pub trait Serializer: Sized {
/// `serialize_seq`. If forwarded, the implementation looks usually just
/// like this:
///
/// ```edition2018
/// ```edition2021
/// # use serde::ser::{Serializer, SerializeSeq};
/// # use serde::__private::doc::Error;
/// #
@@ -740,7 +740,7 @@ pub trait Serializer: Sized {
/// Serialize a [`None`] value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::{Serialize, Serializer};
/// #
/// # enum Option<T> {
@@ -773,7 +773,7 @@ pub trait Serializer: Sized {
/// Serialize a [`Some(T)`] value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::{Serialize, Serializer};
/// #
/// # enum Option<T> {
@@ -808,7 +808,7 @@ pub trait Serializer: Sized {
/// Serialize a `()` value.
///
/// ```edition2018
/// ```edition2021
/// # use serde::Serializer;
/// #
/// # serde::__private_serialize!();
@@ -828,7 +828,7 @@ pub trait Serializer: Sized {
///
/// A reasonable implementation would be to forward to `serialize_unit`.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
///
/// struct Nothing;
@@ -850,7 +850,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, and the `variant` is the name of the
/// variant.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
///
/// enum E {
@@ -883,7 +883,7 @@ pub trait Serializer: Sized {
/// wrappers around the data they contain. A reasonable implementation would
/// be to forward to `value.serialize(self)`.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
///
/// struct Millimeters(u8);
@@ -911,7 +911,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, and the `variant` is the name of the
/// variant. The `value` is the data contained within this newtype variant.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
///
/// enum E {
@@ -949,7 +949,7 @@ pub trait Serializer: Sized {
/// not be computable before the sequence is iterated. Some serializers only
/// support sequences whose length is known up front.
///
/// ```edition2018
/// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # struct Vec<T>(PhantomData<T>);
@@ -962,14 +962,14 @@ pub trait Serializer: Sized {
/// #
/// # impl<'a, T> IntoIterator for &'a Vec<T> {
/// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>;
/// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::ser::{Serialize, Serializer, SerializeSeq};
/// use serde::ser::{Serialize, SerializeSeq, Serializer};
///
/// impl<T> Serialize for Vec<T>
/// where
@@ -994,8 +994,8 @@ pub trait Serializer: Sized {
/// This call must be followed by zero or more calls to `serialize_element`,
/// then a call to `end`.
///
/// ```edition2018
/// use serde::ser::{Serialize, Serializer, SerializeTuple};
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTuple, Serializer};
///
/// # mod fool {
/// # trait Serialize {}
@@ -1024,7 +1024,7 @@ pub trait Serializer: Sized {
/// }
/// ```
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTuple, Serializer};
///
/// const VRAM_SIZE: usize = 386;
@@ -1052,7 +1052,7 @@ pub trait Serializer: Sized {
/// The `name` is the name of the tuple struct and the `len` is the number
/// of data fields that will be serialized.
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
///
/// struct Rgb(u8, u8, u8);
@@ -1084,7 +1084,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, the `variant` is the name of the variant,
/// and the `len` is the number of data fields that will be serialized.
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer};
///
/// enum E {
@@ -1130,7 +1130,7 @@ pub trait Serializer: Sized {
/// be computable before the map is iterated. Some serializers only support
/// maps whose length is known up front.
///
/// ```edition2018
/// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>);
@@ -1143,14 +1143,14 @@ pub trait Serializer: Sized {
/// #
/// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> {
/// # type Item = (&'a K, &'a V);
/// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>;
/// # type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)>>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::ser::{Serialize, Serializer, SerializeMap};
/// use serde::ser::{Serialize, SerializeMap, Serializer};
///
/// impl<K, V> Serialize for HashMap<K, V>
/// where
@@ -1178,7 +1178,7 @@ pub trait Serializer: Sized {
/// The `name` is the name of the struct and the `len` is the number of
/// data fields that will be serialized.
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer};
///
/// struct Rgb {
@@ -1214,7 +1214,7 @@ pub trait Serializer: Sized {
/// this variant within the enum, the `variant` is the name of the variant,
/// and the `len` is the number of data fields that will be serialized.
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeStructVariant, Serializer};
///
/// enum E {
@@ -1256,7 +1256,7 @@ pub trait Serializer: Sized {
/// using [`serialize_seq`]. Implementors should not need to override this
/// method.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
///
/// struct SecretlyOneHigher {
@@ -1304,7 +1304,7 @@ pub trait Serializer: Sized {
/// using [`serialize_map`]. Implementors should not need to override this
/// method.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Serialize, Serializer};
/// use std::collections::BTreeSet;
///
@@ -1355,7 +1355,7 @@ pub trait Serializer: Sized {
/// delegates to [`serialize_str`]. Serializers are encouraged to provide a
/// more efficient implementation if possible.
///
/// ```edition2018
/// ```edition2021
/// # struct DateTime;
/// #
/// # impl DateTime {
@@ -1370,9 +1370,7 @@ pub trait Serializer: Sized {
/// where
/// S: Serializer,
/// {
/// serializer.collect_str(&format_args!("{:?}{:?}",
/// self.naive_local(),
/// self.offset()))
/// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset()))
/// }
/// }
/// ```
@@ -1393,7 +1391,7 @@ pub trait Serializer: Sized {
/// of this method. If no more sensible behavior is possible, the
/// implementation is expected to return an error.
///
/// ```edition2018
/// ```edition2021
/// # struct DateTime;
/// #
/// # impl DateTime {
@@ -1408,9 +1406,7 @@ pub trait Serializer: Sized {
/// where
/// S: Serializer,
/// {
/// serializer.collect_str(&format_args!("{:?}{:?}",
/// self.naive_local(),
/// self.offset()))
/// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset()))
/// }
/// }
/// ```
@@ -1428,7 +1424,7 @@ pub trait Serializer: Sized {
/// human-readable one and binary formats like Postcard will prefer the
/// compact one.
///
/// ```edition2018
/// ```edition2021
/// # use std::fmt::{self, Display};
/// #
/// # struct Timestamp;
@@ -1477,7 +1473,7 @@ pub trait Serializer: Sized {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # struct Vec<T>(PhantomData<T>);
@@ -1490,13 +1486,13 @@ pub trait Serializer: Sized {
/// #
/// # impl<'a, T> IntoIterator for &'a Vec<T> {
/// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>;
/// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::ser::{Serialize, Serializer, SerializeSeq};
/// use serde::ser::{Serialize, SerializeSeq, Serializer};
///
/// impl<T> Serialize for Vec<T>
/// where
@@ -1541,8 +1537,8 @@ pub trait SerializeSeq {
///
/// # Example use
///
/// ```edition2018
/// use serde::ser::{Serialize, Serializer, SerializeTuple};
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTuple, Serializer};
///
/// # mod fool {
/// # trait Serialize {}
@@ -1571,7 +1567,7 @@ pub trait SerializeSeq {
/// }
/// ```
///
/// ```edition2018
/// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # struct Array<T>(PhantomData<T>);
@@ -1584,13 +1580,13 @@ pub trait SerializeSeq {
/// #
/// # impl<'a, T> IntoIterator for &'a Array<T> {
/// # type Item = &'a T;
/// # type IntoIter = Box<Iterator<Item = &'a T>>;
/// # type IntoIter = Box<dyn Iterator<Item = &'a T>>;
/// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::ser::{Serialize, Serializer, SerializeTuple};
/// use serde::ser::{Serialize, SerializeTuple, Serializer};
///
/// # mod fool {
/// # trait Serialize {}
@@ -1641,7 +1637,7 @@ pub trait SerializeTuple {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
///
/// struct Rgb(u8, u8, u8);
@@ -1686,7 +1682,7 @@ pub trait SerializeTupleStruct {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer};
///
/// enum E {
@@ -1744,7 +1740,7 @@ pub trait SerializeTupleVariant {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// # use std::marker::PhantomData;
/// #
/// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>);
@@ -1757,14 +1753,14 @@ pub trait SerializeTupleVariant {
/// #
/// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> {
/// # type Item = (&'a K, &'a V);
/// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>;
/// # type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)>>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # unimplemented!()
/// # }
/// # }
/// #
/// use serde::ser::{Serialize, Serializer, SerializeMap};
/// use serde::ser::{Serialize, SerializeMap, Serializer};
///
/// impl<K, V> Serialize for HashMap<K, V>
/// where
@@ -1855,7 +1851,7 @@ pub trait SerializeMap {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeStruct, Serializer};
///
/// struct Rgb {
@@ -1915,7 +1911,7 @@ pub trait SerializeStruct {
///
/// # Example use
///
/// ```edition2018
/// ```edition2021
/// use serde::ser::{Serialize, SerializeStructVariant, Serializer};
///
/// enum E {
+3 -3
View File
@@ -9,7 +9,7 @@ use lib::{Debug, Display};
/// generally provide their error types with a `std::error::Error` impl
/// directly:
///
/// ```edition2018
/// ```edition2021
/// #[derive(Debug)]
/// struct MySerError {...}
///
@@ -29,7 +29,7 @@ use lib::{Debug, Display};
/// std = ["serde/std"]
/// ```
///
/// ```edition2018
/// ```edition2021
/// #[cfg(feature = "std")]
/// impl std::error::Error for MySerError {}
/// ```
@@ -37,7 +37,7 @@ use lib::{Debug, Display};
/// ... or else provide the std Error impl unconditionally via Serde's
/// re-export:
///
/// ```edition2018
/// ```edition2021
/// impl serde::ser::StdError for MySerError {}
/// ```
pub trait Error: Debug + Display {
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+6 -6
View File
@@ -1,17 +1,16 @@
[package]
name = "serde_derive"
version = "1.0.155" # remember to update html_root_url
version = "1.0.174" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"]
categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
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.31"
rust-version = "1.56"
[features]
default = []
@@ -24,10 +23,11 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0.104"
syn = "2.0.25"
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
serde = { version = "1", path = "../serde" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
-38
View File
@@ -1,38 +0,0 @@
use std::env;
use std::process::Command;
use std::str;
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// Underscore const names stabilized in Rust 1.37:
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
if minor < 37 {
println!("cargo:rustc-cfg=no_underscore_consts");
}
// The ptr::addr_of! macro stabilized in Rust 1.51:
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
if minor < 51 {
println!("cargo:rustc-cfg=no_ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+14 -6
View File
@@ -200,10 +200,16 @@ pub fn with_bound(
for arg in &arguments.args {
match arg {
syn::GenericArgument::Type(arg) => self.visit_type(arg),
syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
syn::GenericArgument::Lifetime(_)
| syn::GenericArgument::Constraint(_)
| syn::GenericArgument::Const(_) => {}
| syn::GenericArgument::Const(_)
| syn::GenericArgument::AssocConst(_)
| syn::GenericArgument::Constraint(_) => {}
#[cfg_attr(
all(test, exhaustive),
deny(non_exhaustive_omitted_patterns)
)]
_ => {}
}
}
}
@@ -226,7 +232,9 @@ pub fn with_bound(
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
match bound {
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
syn::TypeParamBound::Lifetime(_) => {}
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
@@ -251,7 +259,7 @@ pub fn with_bound(
};
match &cont.data {
Data::Enum(variants) => {
for variant in variants.iter() {
for variant in variants {
let relevant_fields = variant
.fields
.iter()
@@ -334,7 +342,7 @@ pub fn with_self_bound(
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let bound = syn::Lifetime::new(lifetime, Span::call_site());
let def = syn::LifetimeDef {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: bound.clone(),
colon_token: None,
+295 -246
View File
@@ -1,5 +1,7 @@
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
#[cfg(precompiled)]
use std::sync::atomic::Ordering;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member};
@@ -15,9 +17,7 @@ use this;
use std::collections::BTreeSet;
use std::ptr;
pub fn expand_derive_deserialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
let ctxt = Ctxt::new();
@@ -69,8 +69,6 @@ pub fn expand_derive_deserialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"DESERIALIZE",
ident,
impl_block,
))
}
@@ -244,9 +242,9 @@ impl BorrowedLifetimes {
}
}
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
fn de_lifetime_param(&self) -> Option<syn::LifetimeParam> {
match self {
BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeDef {
BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
@@ -291,10 +289,10 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
match &cont.data {
Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, fields) => {
deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No)
deserialize_struct(params, fields, &cont.attrs, StructForm::Struct)
}
Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
deserialize_tuple(None, params, fields, &cont.attrs, None)
deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple)
}
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
}
@@ -308,6 +306,11 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
#[cfg(feature = "deserialize_in_place")]
fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<Stmts> {
#[cfg(precompiled)]
if !crate::DESERIALIZE_IN_PLACE.load(Ordering::Relaxed) {
return None;
}
// Only remote derives have getters, and we do not generate
// deserialize_in_place for remote derives.
assert!(!params.has_getter);
@@ -414,15 +417,22 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
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) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
let expecting = format!("unit struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
struct __Visitor;
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
}
impl<'de> _serde::de::Visitor<'de> for __Visitor {
type Value = #this_type;
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)
@@ -437,25 +447,45 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
}
}
_serde::Deserializer::deserialize_unit_struct(__deserializer, #type_name, __Visitor)
_serde::Deserializer::deserialize_unit_struct(
__deserializer,
#type_name,
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
},
)
}
}
enum TupleForm<'a> {
Tuple,
/// Contains a variant name
ExternallyTagged(&'a syn::Ident),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
Untagged(&'a syn::Ident, TokenStream),
}
fn deserialize_tuple(
variant_ident: Option<&syn::Ident>,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
deserializer: Option<TokenStream>,
form: TupleForm,
) -> Fragment {
assert!(!cattrs.has_flatten());
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
// 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.
@@ -466,23 +496,27 @@ fn deserialize_tuple(
quote!(#this_value)
};
let is_enum = variant_ident.is_some();
let type_path = match variant_ident {
Some(variant_ident) => quote!(#construct::#variant_ident),
None => construct,
let type_path = match form {
TupleForm::Tuple => construct,
TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => {
quote!(#construct::#variant_ident)
}
};
let expecting = match variant_ident {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
None => format!("tuple struct {}", params.type_name()),
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 = if !is_enum && nfields == 1 {
Some(deserialize_newtype_struct(&type_path, params, &fields[0]))
} else {
None
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(
@@ -495,26 +529,35 @@ fn deserialize_tuple(
lifetime: _serde::__private::PhantomData,
}
};
let dispatch = if let Some(deserializer) = deserializer {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr))
} else if is_enum {
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))
} else if nfields == 1 {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr))
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(_, deserializer) => quote! {
_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr)
},
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
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 ()>,
@@ -550,13 +593,18 @@ fn deserialize_tuple_in_place(
cattrs: &attr::Container,
deserializer: Option<TokenStream>,
) -> Fragment {
assert!(!cattrs.has_flatten());
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) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
let is_enum = variant_ident.is_some();
let expecting = match variant_ident {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
@@ -582,19 +630,18 @@ fn deserialize_tuple_in_place(
};
let dispatch = if let Some(deserializer) = deserializer {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr))
} else if is_enum {
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr))
} else if nfields == 1 {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
let visitor_var = if field_count == 0 {
quote!(_)
} else {
quote!(mut __seq)
@@ -605,6 +652,7 @@ fn deserialize_tuple_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 ()>,
@@ -894,21 +942,24 @@ fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> To
}
}
enum Untagged {
Yes,
No,
enum StructForm<'a> {
Struct,
/// Contains a variant name
ExternallyTagged(&'a syn::Ident),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
InternallyTagged(&'a syn::Ident, TokenStream),
/// Contains a variant name and an intermediate deserializer from which actual
/// deserialization will be performed
Untagged(&'a syn::Ident, TokenStream),
}
fn deserialize_struct(
variant_ident: Option<&syn::Ident>,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
deserializer: Option<TokenStream>,
untagged: &Untagged,
form: StructForm,
) -> Fragment {
let is_enum = variant_ident.is_some();
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
@@ -925,83 +976,74 @@ fn deserialize_struct(
quote!(#this_value)
};
let type_path = match variant_ident {
Some(variant_ident) => quote!(#construct::#variant_ident),
None => construct,
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 variant_ident {
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
None => format!("struct {}", params.type_name()),
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 visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, true, cattrs, expecting,
let field_names_idents: 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)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let field_visitor = Stmts(deserialize_generated_identifier(
&field_names_idents,
cattrs,
false,
None,
));
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs)
} else {
deserialize_struct_as_struct_visitor(&type_path, params, fields, cattrs)
};
let field_visitor = Stmts(field_visitor);
let fields_stmt = fields_stmt.map(Stmts);
let visit_map = Stmts(visit_map);
let visitor_expr = quote! {
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
}
};
let need_seed = deserializer.is_none();
let dispatch = if let Some(deserializer) = deserializer {
quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
}
} else if is_enum && cattrs.has_flatten() {
quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
}
} else if is_enum {
quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
}
} else if cattrs.has_flatten() {
quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
}
} else {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
quote!(_)
} else {
quote!(mut __seq)
};
// untagged struct variants do not get a visit_seq method. The same applies to
// structs that only have a map representation.
let visit_seq = match *untagged {
Untagged::No if !cattrs.has_flatten() => Some(quote! {
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::__private::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<#delife>,
{
#visit_seq
}
}),
_ => None,
};
let visit_seq = match form {
StructForm::Untagged(..) => None,
_ if cattrs.has_flatten() => None,
_ => {
let mut_seq = if field_names_idents.is_empty() {
quote!(_)
} else {
quote!(mut __seq)
};
let visitor_seed = if need_seed && is_enum && cattrs.has_flatten() {
Some(quote! {
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));
let visitor_seed = match form {
StructForm::ExternallyTagged(..) if cattrs.has_flatten() => Some(quote! {
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
@@ -1012,14 +1054,57 @@ fn deserialize_struct(
_serde::Deserializer::deserialize_map(__deserializer, self)
}
}
})
} else {
}),
_ => None,
};
let fields_stmt = if cattrs.has_flatten() {
None
} else {
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
Some(quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
})
};
let visitor_expr = quote! {
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
}
};
let dispatch = match form {
StructForm::Struct if cattrs.has_flatten() => quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
},
StructForm::Struct => {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
}
StructForm::ExternallyTagged(_) if cattrs.has_flatten() => quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
},
StructForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
},
StructForm::InternallyTagged(_, deserializer) => quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
},
StructForm::Untagged(_, deserializer) => quote! {
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
},
};
quote_block! {
#field_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1132,6 +1217,7 @@ fn deserialize_struct_in_place(
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 ()>,
@@ -1165,6 +1251,22 @@ fn deserialize_enum(
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));
deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag))
}
None => deserialize_homogeneous_enum(params, variants, cattrs),
}
}
fn deserialize_homogeneous_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
match cattrs.tag() {
attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs),
@@ -1203,6 +1305,7 @@ fn prepare_enum_variant_enum(
let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
};
@@ -1275,6 +1378,7 @@ fn deserialize_externally_tagged_enum(
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 ()>,
@@ -1329,9 +1433,7 @@ fn deserialize_internally_tagged_enum(
params,
variant,
cattrs,
quote! {
_serde::__private::de::ContentDeserializer::<__D::Error>::new(__tagged.content)
},
quote!(__deserializer),
));
quote! {
@@ -1347,11 +1449,12 @@ fn deserialize_internally_tagged_enum(
#variants_stmt
let __tagged = try!(_serde::Deserializer::deserialize_any(
let (__tag, __content) = try!(_serde::Deserializer::deserialize_any(
__deserializer,
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting)));
let __deserializer = _serde::__private::de::ContentDeserializer::<__D::Error>::new(__content);
match __tagged.tag {
match __tag {
#(#variant_arms)*
}
}
@@ -1522,6 +1625,7 @@ fn deserialize_adjacently_tagged_enum(
#variants_stmt
#[doc(hidden)]
struct __Seed #de_impl_generics #where_clause {
field: __Field,
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1541,6 +1645,7 @@ fn deserialize_adjacently_tagged_enum(
}
}
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1643,6 +1748,7 @@ fn deserialize_adjacently_tagged_enum(
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content];
_serde::Deserializer::deserialize_struct(
__deserializer,
@@ -1660,6 +1766,16 @@ fn deserialize_untagged_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let first_attempt = None;
deserialize_untagged_enum_after(params, variants, cattrs, first_attempt)
}
fn deserialize_untagged_enum_after(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
first_attempt: Option<Expr>,
) -> Fragment {
let attempts = variants
.iter()
@@ -1669,12 +1785,10 @@ fn deserialize_untagged_enum(
params,
variant,
cattrs,
quote!(
_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)
),
quote!(__deserializer),
))
});
let attempts = first_attempt.into_iter().chain(attempts);
// 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
@@ -1689,6 +1803,7 @@ fn deserialize_untagged_enum(
quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
#(
if let _serde::__private::Ok(__ok) = #attempts {
@@ -1730,16 +1845,17 @@ fn deserialize_externally_tagged_variant(
&variant.fields[0],
cattrs,
),
Style::Tuple => {
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
}
Style::Struct => deserialize_struct(
Some(variant_ident),
Style::Tuple => deserialize_tuple(
params,
&variant.fields,
cattrs,
None,
&Untagged::No,
TupleForm::ExternallyTagged(variant_ident),
),
Style::Struct => deserialize_struct(
params,
&variant.fields,
cattrs,
StructForm::ExternallyTagged(variant_ident),
),
}
}
@@ -1779,12 +1895,10 @@ fn deserialize_internally_tagged_variant(
&deserializer,
),
Style::Struct => deserialize_struct(
Some(variant_ident),
params,
&variant.fields,
cattrs,
Some(deserializer),
&Untagged::No,
StructForm::InternallyTagged(variant_ident, deserializer),
),
Style::Tuple => unreachable!("checked in serde_derive_internals"),
}
@@ -1831,19 +1945,16 @@ fn deserialize_untagged_variant(
&deserializer,
),
Style::Tuple => deserialize_tuple(
Some(variant_ident),
params,
&variant.fields,
cattrs,
Some(deserializer),
TupleForm::Untagged(variant_ident, deserializer),
),
Style::Struct => deserialize_struct(
Some(variant_ident),
params,
&variant.fields,
cattrs,
Some(deserializer),
&Untagged::Yes,
StructForm::Untagged(variant_ident, deserializer),
),
}
}
@@ -1954,11 +2065,13 @@ fn deserialize_generated_identifier(
quote_block! {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field #lifetime {
#(#field_idents,)*
#ignore_variant
}
#[doc(hidden)]
struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
@@ -2046,11 +2159,13 @@ fn deserialize_custom_identifier(
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)
@@ -2072,6 +2187,7 @@ fn deserialize_custom_identifier(
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 ()>,
@@ -2379,70 +2495,6 @@ fn deserialize_identifier(
}
}
fn deserialize_struct_as_struct_visitor(
struct_path: &TokenStream,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Option<Fragment>, Fragment) {
assert!(!cattrs.has_flatten());
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing())
.map(|(i, field)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let fields_stmt = {
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
};
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
(field_visitor, Some(fields_stmt), visit_map)
}
fn deserialize_struct_as_map_visitor(
struct_path: &TokenStream,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Option<Fragment>, Fragment) {
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(i, field)| {
(
field.attrs.name().deserialize_name(),
field_i(i),
field.attrs.aliases(),
)
})
.collect();
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
(field_visitor, None, visit_map)
}
fn deserialize_map(
struct_path: &TokenStream,
params: &Parameters,
@@ -2684,6 +2736,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
let fields_stmt = {
let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
};
@@ -2864,6 +2917,7 @@ fn wrap_deserialize_with(
let delife = params.borrowed.de_lifetime();
let wrapper = quote! {
#[doc(hidden)]
struct __DeserializeWith #de_impl_generics #where_clause {
value: #value_ty,
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -3011,7 +3065,7 @@ struct InPlaceImplGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() {
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
@@ -3046,7 +3100,7 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
.into_iter()
.chain(generics.params)
.collect();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() {
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
@@ -3068,23 +3122,31 @@ struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")]
struct InPlaceTypeGenerics<'a>(&'a Parameters);
fn de_type_generics_to_tokens(
mut generics: syn::Generics,
borrowed: &BorrowedLifetimes,
tokens: &mut TokenStream,
) {
if borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
// Prepend 'de lifetime to list of generics
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens);
}
}
@@ -3097,20 +3159,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
.chain(generics.params)
.collect();
if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(generics, &self.0.borrowed, tokens);
}
}
@@ -3122,8 +3171,8 @@ impl<'a> DeTypeGenerics<'a> {
}
#[cfg(feature = "deserialize_in_place")]
fn place_lifetime() -> syn::LifetimeDef {
syn::LifetimeDef {
fn place_lifetime() -> syn::LifetimeParam {
syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'place", Span::call_site()),
colon_token: None,
+3 -19
View File
@@ -1,23 +1,11 @@
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use proc_macro2::TokenStream;
use syn;
use try;
pub fn wrap_in_const(
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
let try_replacement = try::replacement();
let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};
let use_serde = match serde_path {
Some(path) => quote! {
use #path as _serde;
@@ -31,14 +19,10 @@ pub fn wrap_in_const(
quote! {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
const _: () = {
#use_serde
#try_replacement
#code
};
}
}
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
+15 -2
View File
@@ -140,7 +140,7 @@ fn enum_from_ast<'a>(
variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default,
) -> Vec<Variant<'a>> {
variants
let variants: Vec<Variant> = variants
.iter()
.map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
@@ -154,7 +154,20 @@ fn enum_from_ast<'a>(
original: variant,
}
})
.collect()
.collect();
let index_of_last_tagged_variant = variants
.iter()
.rposition(|variant| !variant.attrs.untagged());
if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant {
for variant in &variants[..index_of_last_tagged_variant] {
if variant.attrs.untagged() {
cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");
}
}
}
variants
}
fn struct_from_ast<'a>(
File diff suppressed because it is too large Load Diff
+34 -39
View File
@@ -3,8 +3,8 @@ use internals::attr::{Identifier, TagType};
use internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type};
/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
// Cross-cutting checks that require looking at more than a single attrs object.
// Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_remote_generic(cx, cont);
check_getter(cx, cont);
@@ -17,18 +17,18 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_from_and_try_from(cx, cont);
}
/// Remote derive definition type must have either all of the generics of the
/// remote type:
///
/// #[serde(remote = "Generic")]
/// struct Generic<T> {…}
///
/// or none of them, i.e. defining impls for one concrete instantiation of the
/// remote type only:
///
/// #[serde(remote = "Generic<T>")]
/// struct ConcreteDef {…}
///
// Remote derive definition type must have either all of the generics of the
// remote type:
//
// #[serde(remote = "Generic")]
// struct Generic<T> {…}
//
// or none of them, i.e. defining impls for one concrete instantiation of the
// remote type only:
//
// #[serde(remote = "Generic<T>")]
// struct ConcreteDef {…}
//
fn check_remote_generic(cx: &Ctxt, cont: &Container) {
if let Some(remote) = cont.attrs.remote() {
let local_has_generic = !cont.generics.params.is_empty();
@@ -39,8 +39,8 @@ fn check_remote_generic(cx: &Ctxt, cont: &Container) {
}
}
/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
// Getters are only allowed inside structs (not enums) with the `remote`
// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.data {
Data::Enum(_) => {
@@ -62,7 +62,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
}
}
/// Flattening has some restrictions we can test.
// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) {
match &cont.data {
Data::Enum(variants) => {
@@ -101,18 +101,16 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
}
}
/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
// The `other` attribute must be used at most once and it must be the last
// variant of an enum.
//
// Inside a `variant_identifier` all variants must be unit variants. Inside a
// `field_identifier` all but possibly one variant must be unit variants. The
// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
Data::Struct(_, _) => {
return;
}
Data::Struct(_, _) => return,
};
for (i, variant) in variants.iter().enumerate() {
@@ -189,17 +187,15 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
}
}
/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
// Skip-(de)serializing attributes are not allowed on variants marked
// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
Data::Struct(_, _) => {
return;
}
Data::Struct(_, _) => return,
};
for variant in variants.iter() {
for variant in variants {
if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() {
cx.error_spanned_by(
@@ -264,10 +260,9 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
}
}
/// The tag of an internally-tagged struct variant must not be
/// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input.
// The tag of an internally-tagged struct variant must not be the same as either
// one of its fields, as this would result in duplicate keys in the serialized
// output and/or ambiguity in the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
@@ -313,8 +308,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
}
}
/// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason.
// In the case of adjacently-tagged enums, the type and the contents tag must
// differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match cont.attrs.tag() {
TagType::Adjacent { tag, content } => (tag, content),
@@ -332,7 +327,7 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
}
}
/// Enums and unit structs cannot be transparent.
// Enums and unit structs cannot be transparent.
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
if !cont.attrs.transparent() {
return;
+12 -5
View File
@@ -44,12 +44,19 @@ impl Ctxt {
}
/// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> Result<(), Vec<syn::Error>> {
let errors = self.errors.borrow_mut().take().unwrap();
match errors.len() {
0 => Ok(()),
_ => Err(errors),
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(()),
};
for rest in errors {
combined.combine(rest);
}
Err(combined)
}
}
+12 -5
View File
@@ -179,10 +179,13 @@ impl ReplaceReceiver<'_> {
for arg in &mut arguments.args {
match arg {
GenericArgument::Type(arg) => self.visit_type_mut(arg),
GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty),
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
GenericArgument::Lifetime(_)
| GenericArgument::Constraint(_)
| GenericArgument::Const(_) => {}
| GenericArgument::Const(_)
| GenericArgument::AssocConst(_)
| GenericArgument::Constraint(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
}
@@ -205,7 +208,9 @@ impl ReplaceReceiver<'_> {
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
match bound {
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
TypeParamBound::Lifetime(_) => {}
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
@@ -229,7 +234,9 @@ impl ReplaceReceiver<'_> {
self.visit_type_param_bound_mut(bound);
}
}
WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {}
WherePredicate::Lifetime(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
}
+26 -12
View File
@@ -1,7 +1,7 @@
//! This crate provides Serde's two derive macros.
//!
//! ```edition2018
//! # use serde_derive::{Serialize, Deserialize};
//! ```edition2021
//! # use serde_derive::{Deserialize, Serialize};
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
@@ -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.155")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.174")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
@@ -68,12 +68,18 @@ extern crate quote;
#[macro_use]
extern crate syn;
#[cfg(not(precompiled))]
extern crate proc_macro;
extern crate proc_macro2;
#[cfg(precompiled)]
extern crate proc_macro2 as proc_macro;
mod internals;
use proc_macro::TokenStream;
#[cfg(precompiled)]
use std::sync::atomic::AtomicBool;
use syn::DeriveInput;
#[macro_use]
@@ -88,23 +94,31 @@ mod ser;
mod this;
mod try;
#[proc_macro_derive(Serialize, attributes(serde))]
#[cfg(precompiled)]
macro_rules! parse_macro_input {
($tokenstream:ident as $ty:ty) => {
match syn::parse2::<$ty>($tokenstream) {
Ok(data) => data,
Err(err) => return err.to_compile_error(),
}
};
}
#[cfg(precompiled)]
pub static DESERIALIZE_IN_PLACE: AtomicBool = AtomicBool::new(false);
#[cfg_attr(not(precompiled), proc_macro_derive(Serialize, attributes(serde)))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(to_compile_errors)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
#[cfg_attr(not(precompiled), proc_macro_derive(Deserialize, attributes(serde)))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(to_compile_errors)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
+7 -22
View File
@@ -97,29 +97,14 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(not(no_ptr_addr_of))]
{
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
#[cfg(no_ptr_addr_of)]
{
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
+11 -10
View File
@@ -10,9 +10,7 @@ use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend;
use this;
pub fn expand_derive_serialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
let ctxt = Ctxt::new();
@@ -59,8 +57,6 @@ pub fn expand_derive_serialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"SERIALIZE",
ident,
impl_block,
))
}
@@ -477,17 +473,19 @@ fn serialize_variant(
}
};
let body = Match(match cattrs.tag() {
attr::TagType::External => {
let body = Match(match (cattrs.tag(), variant.attrs.untagged()) {
(attr::TagType::External, false) => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
}
attr::TagType::Internal { tag } => {
(attr::TagType::Internal { tag }, false) => {
serialize_internally_tagged_variant(params, variant, cattrs, tag)
}
attr::TagType::Adjacent { tag, content } => {
(attr::TagType::Adjacent { tag, content }, false) => {
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
}
attr::TagType::None => serialize_untagged_variant(params, variant, cattrs),
(attr::TagType::None, _) | (_, true) => {
serialize_untagged_variant(params, variant, cattrs)
}
});
quote! {
@@ -719,6 +717,7 @@ fn serialize_adjacently_tagged_variant(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
#[doc(hidden)]
struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -982,6 +981,7 @@ fn serialize_struct_variant_with_flatten(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
#[doc(hidden)]
struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1212,6 +1212,7 @@ fn wrap_serialize_with(
});
quote!({
#[doc(hidden)]
struct __SerializeWith #wrapper_impl_generics #where_clause {
values: (#(&'__a #field_tys, )*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+5 -4
View File
@@ -1,15 +1,15 @@
[package]
name = "serde_derive_internals"
version = "0.26.0" # remember to update html_root_url
version = "0.28.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals"
exclude = ["build.rs"]
homepage = "https://serde.rs"
include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.31"
rust-version = "1.56"
[lib]
path = "lib.rs"
@@ -17,7 +17,8 @@ path = "lib.rs"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.104", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
syn = { version = "2.0.25", default-features = false, features = ["clone-impls", "derive", "parsing", "printing"] }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
+2 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
@@ -31,6 +31,7 @@
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::unused_self,
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+4 -4
View File
@@ -1,13 +1,12 @@
[package]
name = "serde_test"
version = "1.0.155" # remember to update html_root_url
version = "1.0.174" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["development-tools::testing"]
description = "Token De/Serializer for testing De/Serialize implementations"
documentation = "https://docs.rs/serde_test"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "testing", "dev-dependencies"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
@@ -18,11 +17,12 @@ rust-version = "1.19"
serde = { version = "1.0.60", path = "../serde" }
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
serde_derive = { version = "1.0", path = "../serde_derive" }
serde = { version = "1", path = "../serde", features = ["rc"] }
serde_derive = { version = "1", path = "../serde_derive" }
[lib]
doc-scrape-examples = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
+54 -40
View File
@@ -8,8 +8,8 @@ use std::fmt::Debug;
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -19,14 +19,17 @@ use std::fmt::Debug;
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ]);
/// assert_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
@@ -39,8 +42,8 @@ where
/// Asserts that `value` serializes to the given `tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_ser_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -50,14 +53,17 @@ where
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(&s, &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ]);
/// assert_ser_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token])
@@ -78,23 +84,24 @@ where
/// Asserts that `value` serializes to the given `tokens`, and then yields
/// `error`.
///
/// ```edition2018
/// ```edition2021
/// use serde_derive::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// use serde::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)]
/// struct Example {
/// lock: Arc<Mutex<u32>>,
/// }
///
/// fn main() {
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
/// let example = Example {
/// lock: Arc::new(Mutex::new(0)),
/// };
/// let lock = example.lock.clone();
///
/// let _ = thread::spawn(move || {
/// let thread = thread::spawn(move || {
/// // This thread will acquire the mutex first, unwrapping the result
/// // of `lock` because the lock has not been poisoned.
/// let _guard = lock.lock().unwrap();
@@ -102,10 +109,14 @@ where
/// // This panic while holding the lock (`_guard` is in scope) will
/// // poison the mutex.
/// panic!()
/// }).join();
/// });
/// thread.join();
///
/// let expected = &[
/// Token::Struct { name: "Example", len: 1 },
/// Token::Struct {
/// name: "Example",
/// len: 1,
/// },
/// Token::Str("lock"),
/// ];
/// let error = "lock poison error while serializing";
@@ -130,8 +141,8 @@ where
/// Asserts that the given `tokens` deserialize into `value`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -141,14 +152,17 @@ where
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_de_tokens(&s, &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ]);
/// assert_de_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
@@ -184,8 +198,8 @@ where
/// Asserts that the given `tokens` yield `error` when deserializing.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens_error, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct Compact<T: ?Sized>(T);
/// Trait to determine whether a value is represented in human-readable or
/// compact form.
///
/// ```edition2018
/// ```edition2021
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{assert_tokens, Configure, Token};
///
+83 -95
View File
@@ -12,32 +12,29 @@ pub struct Deserializer<'de> {
tokens: &'de [Token],
}
macro_rules! assert_next_token {
($de:expr, $expected:expr) => {
match $de.next_token_opt() {
Some(token) if token == $expected => {}
Some(other) => panic!(
"expected Token::{} but deserialization wants Token::{}",
other, $expected
),
None => panic!(
"end of tokens but deserialization wants Token::{}",
$expected
),
}
};
fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
match de.next_token_opt() {
Some(token) if token == expected => Ok(()),
Some(other) => Err(de::Error::custom(format!(
"expected Token::{} but deserialization wants Token::{}",
other, expected,
))),
None => Err(de::Error::custom(format!(
"end of tokens but deserialization wants Token::{}",
expected,
))),
}
}
macro_rules! unexpected {
($token:expr) => {
panic!("deserialization did not expect this token: {}", $token)
};
fn unexpected(token: Token) -> Error {
de::Error::custom(format!(
"deserialization did not expect this token: {}",
token,
))
}
macro_rules! end_of_tokens {
() => {
panic!("ran out of tokens to deserialize")
};
fn end_of_tokens() -> Error {
de::Error::custom("ran out of tokens to deserialize")
}
impl<'de> Deserializer<'de> {
@@ -49,11 +46,8 @@ impl<'de> Deserializer<'de> {
self.tokens.first().cloned()
}
fn peek_token(&self) -> Token {
match self.peek_token_opt() {
Some(token) => token,
None => end_of_tokens!(),
}
fn peek_token(&self) -> Result<Token, Error> {
self.peek_token_opt().ok_or_else(end_of_tokens)
}
pub fn next_token_opt(&mut self) -> Option<Token> {
@@ -66,14 +60,10 @@ impl<'de> Deserializer<'de> {
}
}
fn next_token(&mut self) -> Token {
match self.tokens.split_first() {
Some((&first, rest)) => {
self.tokens = rest;
first
}
None => end_of_tokens!(),
}
fn next_token(&mut self) -> Result<Token, Error> {
let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
self.tokens = rest;
Ok(first)
}
pub fn remaining(&self) -> usize {
@@ -94,7 +84,7 @@ impl<'de> Deserializer<'de> {
len: len,
end: end,
})?;
assert_next_token!(self, end);
assert_next_token(self, end)?;
Ok(value)
}
@@ -112,7 +102,7 @@ impl<'de> Deserializer<'de> {
len: len,
end: end,
})?;
assert_next_token!(self, end);
assert_next_token(self, end)?;
Ok(value)
}
}
@@ -129,7 +119,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
let token = self.next_token();
let token = self.next_token()?;
match token {
Token::Bool(v) => visitor.visit_bool(v),
Token::I8(v) => visitor.visit_i8(v),
@@ -161,50 +151,50 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => {
let variant = self.next_token();
let next = self.peek_token();
let variant = self.next_token()?;
let next = self.peek_token()?;
match (variant, next) {
(Token::Str(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_str(variant)
}
(Token::BorrowedStr(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_borrowed_str(variant)
}
(Token::String(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_string(variant.to_string())
}
(Token::Bytes(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_bytes(variant)
}
(Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_borrowed_bytes(variant)
}
(Token::ByteBuf(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_byte_buf(variant.to_vec())
}
(Token::U8(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u8(variant)
}
(Token::U16(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u16(variant)
}
(Token::U32(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u32(variant)
}
(Token::U64(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u64(variant)
}
(variant, Token::Unit) => unexpected!(variant),
(variant, Token::Unit) => Err(unexpected(variant)),
(variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
}
@@ -232,9 +222,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
| Token::MapEnd
| Token::StructEnd
| Token::TupleVariantEnd
| Token::StructVariantEnd => {
unexpected!(token);
}
| Token::StructVariantEnd => Err(unexpected(token)),
}
}
@@ -242,13 +230,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit | Token::None => {
self.next_token();
self.next_token()?;
visitor.visit_none()
}
Token::Some => {
self.next_token();
self.next_token()?;
visitor.visit_some(self)
}
_ => self.deserialize_any(visitor),
@@ -264,9 +252,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Enum { name: n } if name == n => {
self.next_token();
self.next_token()?;
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
@@ -286,9 +274,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
_ => self.deserialize_any(visitor),
@@ -303,9 +291,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::NewtypeStruct { .. } => {
assert_next_token!(self, Token::NewtypeStruct { name: name });
assert_next_token(self, Token::NewtypeStruct { name: name })?;
visitor.visit_newtype_struct(self)
}
_ => self.deserialize_any(visitor),
@@ -316,21 +304,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit | Token::UnitStruct { .. } => {
self.next_token();
self.next_token()?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -346,25 +334,25 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit => {
self.next_token();
self.next_token()?;
visitor.visit_unit()
}
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { len: n, .. } => {
assert_next_token!(self, Token::TupleStruct { name: name, len: n });
assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -380,13 +368,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Struct { len: n, .. } => {
assert_next_token!(self, Token::Struct { name: name, len: n });
assert_next_token(self, Token::Struct { name: name, len: n })?;
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
}
Token::Map { .. } => {
self.next_token();
self.next_token()?;
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -476,7 +464,7 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: DeserializeSeed<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. }
@@ -497,9 +485,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token() {
match self.de.peek_token()? {
Token::UnitVariant { .. } => {
self.de.next_token();
self.de.next_token()?;
Ok(())
}
_ => Deserialize::deserialize(self.de),
@@ -510,9 +498,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
T: DeserializeSeed<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::NewtypeVariant { .. } => {
self.de.next_token();
self.de.next_token()?;
seed.deserialize(self.de)
}
_ => seed.deserialize(self.de),
@@ -523,26 +511,26 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: Visitor<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if len == enum_len {
self.de
.visit_seq(Some(len), Token::TupleVariantEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
Token::Seq {
len: Some(enum_len),
} => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if len == enum_len {
self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -557,27 +545,27 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: Visitor<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
Token::Map {
len: Some(enum_len),
} => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::MapEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -622,7 +610,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
.deserialize(BytesDeserializer { value: variant })
.map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other),
Some(other) => Err(unexpected(other)),
None => Ok(None),
}
}
@@ -641,7 +629,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
};
seed.deserialize(SeqAccessDeserializer::new(visitor))?
};
assert_next_token!(self.de, Token::TupleVariantEnd);
assert_next_token(self.de, Token::TupleVariantEnd)?;
Ok(value)
}
EnumFormat::Map => {
@@ -653,7 +641,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
};
seed.deserialize(MapAccessDeserializer::new(visitor))?
};
assert_next_token!(self.de, Token::StructVariantEnd);
assert_next_token(self.de, Token::StructVariantEnd)?;
Ok(value)
}
EnumFormat::Any => seed.deserialize(&mut *self.de),
+23 -23
View File
@@ -20,11 +20,11 @@
//!
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
//!
//! ```edition2018
//! ```edition2021
//! # const IGNORE: &str = stringify! {
//! use linked_hash_map::LinkedHashMap;
//! # };
//! use serde_test::{Token, assert_tokens};
//! use serde_test::{assert_tokens, Token};
//!
//! # use std::fmt;
//! # use std::marker::PhantomData;
@@ -106,10 +106,13 @@
//! fn test_ser_de_empty() {
//! let map = LinkedHashMap::<char, u32>::new();
//!
//! assert_tokens(&map, &[
//! Token::Map { len: Some(0) },
//! Token::MapEnd,
//! ]);
//! assert_tokens(
//! &map,
//! &[
//! Token::Map { len: Some(0) },
//! Token::MapEnd,
//! ],
//! );
//! }
//!
//! #[test]
@@ -120,18 +123,19 @@
//! map.insert('a', 10);
//! map.insert('c', 30);
//!
//! assert_tokens(&map, &[
//! Token::Map { len: Some(3) },
//! Token::Char('b'),
//! Token::I32(20),
//!
//! Token::Char('a'),
//! Token::I32(10),
//!
//! Token::Char('c'),
//! Token::I32(30),
//! Token::MapEnd,
//! ]);
//! assert_tokens(
//! &map,
//! &[
//! Token::Map { len: Some(3) },
//! Token::Char('b'),
//! Token::I32(20),
//! Token::Char('a'),
//! Token::I32(10),
//! Token::Char('c'),
//! Token::I32(30),
//! Token::MapEnd,
//! ],
//! );
//! }
//! #
//! # fn main() {
@@ -140,7 +144,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.155")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.174")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
@@ -182,7 +186,3 @@ pub use assert::{
pub use token::Token;
pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
+6 -8
View File
@@ -63,14 +63,12 @@ macro_rules! assert_next_token {
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
Some(expected) => {
panic!("expected Token::{} but serialized as {}",
expected, $actual);
}
None => {
panic!("expected end of tokens, but {} was serialized",
$actual);
}
Some(expected) => return Err(ser::Error::custom(
format!("expected Token::{} but serialized as {}", expected, $actual)
)),
None => return Err(ser::Error::custom(
format!("expected end of tokens, but {} was serialized", $actual)
)),
}
};
}
+167 -125
View File
@@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Display};
pub enum Token {
/// A serialized `bool`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&true, &[Token::Bool(true)]);
@@ -13,7 +13,7 @@ pub enum Token {
/// A serialized `i8`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i8, &[Token::I8(0)]);
@@ -22,7 +22,7 @@ pub enum Token {
/// A serialized `i16`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i16, &[Token::I16(0)]);
@@ -31,7 +31,7 @@ pub enum Token {
/// A serialized `i32`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i32, &[Token::I32(0)]);
@@ -40,7 +40,7 @@ pub enum Token {
/// A serialized `i64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i64, &[Token::I64(0)]);
@@ -49,7 +49,7 @@ pub enum Token {
/// A serialized `u8`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u8, &[Token::U8(0)]);
@@ -58,7 +58,7 @@ pub enum Token {
/// A serialized `u16`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u16, &[Token::U16(0)]);
@@ -67,7 +67,7 @@ pub enum Token {
/// A serialized `u32`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u32, &[Token::U32(0)]);
@@ -76,7 +76,7 @@ pub enum Token {
/// A serialized `u64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u64, &[Token::U64(0)]);
@@ -85,7 +85,7 @@ pub enum Token {
/// A serialized `f32`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
@@ -94,7 +94,7 @@ pub enum Token {
/// A serialized `f64`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
@@ -103,7 +103,7 @@ pub enum Token {
/// A serialized `char`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&'\n', &[Token::Char('\n')]);
@@ -112,7 +112,7 @@ pub enum Token {
/// A serialized `str`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s = String::from("transient");
@@ -122,7 +122,7 @@ pub enum Token {
/// A borrowed `str`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s: &str = "borrowed";
@@ -132,7 +132,7 @@ pub enum Token {
/// A serialized `String`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s = String::from("owned");
@@ -151,7 +151,7 @@ pub enum Token {
/// A serialized `Option<T>` containing none.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let opt = None::<char>;
@@ -163,20 +163,17 @@ pub enum Token {
///
/// The tokens of the value follow after this header.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let opt = Some('c');
/// assert_tokens(&opt, &[
/// Token::Some,
/// Token::Char('c'),
/// ]);
/// assert_tokens(&opt, &[Token::Some, Token::Char('c')]);
/// ```
Some,
/// A serialized `()`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&(), &[Token::Unit]);
@@ -185,8 +182,8 @@ pub enum Token {
/// A serialized unit struct of the given name.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -200,8 +197,8 @@ pub enum Token {
/// A unit variant of an enum.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -211,7 +208,13 @@ pub enum Token {
/// }
///
/// let a = E::A;
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]);
/// assert_tokens(
/// &a,
/// &[Token::UnitVariant {
/// name: "E",
/// variant: "A",
/// }],
/// );
/// # }
/// ```
UnitVariant {
@@ -223,8 +226,8 @@ pub enum Token {
///
/// After this header is the value contained in the newtype struct.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -232,10 +235,10 @@ pub enum Token {
/// struct N(String);
///
/// let n = N("newtype".to_owned());
/// assert_tokens(&n, &[
/// Token::NewtypeStruct { name: "N" },
/// Token::String("newtype"),
/// ]);
/// assert_tokens(
/// &n,
/// &[Token::NewtypeStruct { name: "N" }, Token::String("newtype")],
/// );
/// # }
/// ```
NewtypeStruct { name: &'static str },
@@ -244,8 +247,8 @@ pub enum Token {
///
/// After this header is the value contained in the newtype variant.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -255,10 +258,16 @@ pub enum Token {
/// }
///
/// let b = E::B(0);
/// assert_tokens(&b, &[
/// Token::NewtypeVariant { name: "E", variant: "B" },
/// Token::U8(0),
/// ]);
/// assert_tokens(
/// &b,
/// &[
/// Token::NewtypeVariant {
/// name: "E",
/// variant: "B",
/// },
/// Token::U8(0),
/// ],
/// );
/// # }
/// ```
NewtypeVariant {
@@ -271,17 +280,20 @@ pub enum Token {
/// After this header are the elements of the sequence, followed by
/// `SeqEnd`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let vec = vec!['a', 'b', 'c'];
/// assert_tokens(&vec, &[
/// Token::Seq { len: Some(3) },
/// Token::Char('a'),
/// Token::Char('b'),
/// Token::Char('c'),
/// Token::SeqEnd,
/// ]);
/// assert_tokens(
/// &vec,
/// &[
/// Token::Seq { len: Some(3) },
/// Token::Char('a'),
/// Token::Char('b'),
/// Token::Char('c'),
/// Token::SeqEnd,
/// ],
/// );
/// ```
Seq { len: Option<usize> },
@@ -292,16 +304,19 @@ pub enum Token {
///
/// After this header are the elements of the tuple, followed by `TupleEnd`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let tuple = ('a', 100);
/// assert_tokens(&tuple, &[
/// Token::Tuple { len: 2 },
/// Token::Char('a'),
/// Token::I32(100),
/// Token::TupleEnd,
/// ]);
/// assert_tokens(
/// &tuple,
/// &[
/// Token::Tuple { len: 2 },
/// Token::Char('a'),
/// Token::I32(100),
/// Token::TupleEnd,
/// ],
/// );
/// ```
Tuple { len: usize },
@@ -313,8 +328,8 @@ pub enum Token {
/// After this header are the fields of the tuple struct, followed by
/// `TupleStructEnd`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -322,12 +337,15 @@ pub enum Token {
/// struct T(u8, u8);
///
/// let t = T(0, 0);
/// assert_tokens(&t, &[
/// Token::TupleStruct { name: "T", len: 2 },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleStructEnd,
/// ]);
/// assert_tokens(
/// &t,
/// &[
/// Token::TupleStruct { name: "T", len: 2 },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleStructEnd,
/// ],
/// );
/// # }
/// ```
TupleStruct { name: &'static str, len: usize },
@@ -340,8 +358,8 @@ pub enum Token {
/// After this header are the fields of the tuple variant, followed by
/// `TupleVariantEnd`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -351,12 +369,19 @@ pub enum Token {
/// }
///
/// let c = E::C(0, 0);
/// assert_tokens(&c, &[
/// Token::TupleVariant { name: "E", variant: "C", len: 2 },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleVariantEnd,
/// ]);
/// assert_tokens(
/// &c,
/// &[
/// Token::TupleVariant {
/// name: "E",
/// variant: "C",
/// len: 2,
/// },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleVariantEnd,
/// ],
/// );
/// # }
/// ```
TupleVariant {
@@ -372,7 +397,7 @@ pub enum Token {
///
/// After this header are the entries of the map, followed by `MapEnd`.
///
/// ```edition2018
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// use std::collections::BTreeMap;
@@ -381,14 +406,17 @@ pub enum Token {
/// map.insert('A', 65);
/// map.insert('Z', 90);
///
/// assert_tokens(&map, &[
/// Token::Map { len: Some(2) },
/// Token::Char('A'),
/// Token::I32(65),
/// Token::Char('Z'),
/// Token::I32(90),
/// Token::MapEnd,
/// ]);
/// assert_tokens(
/// &map,
/// &[
/// Token::Map { len: Some(2) },
/// Token::Char('A'),
/// Token::I32(65),
/// Token::Char('Z'),
/// Token::I32(90),
/// Token::MapEnd,
/// ],
/// );
/// ```
Map { len: Option<usize> },
@@ -399,8 +427,8 @@ pub enum Token {
///
/// After this header are the fields of the struct, followed by `StructEnd`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -411,14 +439,17 @@ pub enum Token {
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ]);
/// assert_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// # }
/// ```
Struct { name: &'static str, len: usize },
@@ -431,8 +462,8 @@ pub enum Token {
/// After this header are the fields of the struct variant, followed by
/// `StructVariantEnd`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -442,12 +473,19 @@ pub enum Token {
/// }
///
/// let d = E::D { d: 0 };
/// assert_tokens(&d, &[
/// Token::StructVariant { name: "E", variant: "D", len: 1 },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::StructVariantEnd,
/// ]);
/// assert_tokens(
/// &d,
/// &[
/// Token::StructVariant {
/// name: "E",
/// variant: "D",
/// len: 1,
/// },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::StructVariantEnd,
/// ],
/// );
/// # }
/// ```
StructVariant {
@@ -461,8 +499,8 @@ pub enum Token {
/// The header to an enum of the given name.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
@@ -475,38 +513,42 @@ pub enum Token {
/// }
///
/// let a = E::A;
/// assert_tokens(&a, &[
/// Token::Enum { name: "E" },
/// Token::Str("A"),
/// Token::Unit,
/// ]);
/// assert_tokens(
/// &a,
/// &[Token::Enum { name: "E" }, Token::Str("A"), Token::Unit],
/// );
///
/// let b = E::B(0);
/// assert_tokens(&b, &[
/// Token::Enum { name: "E" },
/// Token::Str("B"),
/// Token::U8(0),
/// ]);
/// assert_tokens(
/// &b,
/// &[Token::Enum { name: "E" }, Token::Str("B"), Token::U8(0)],
/// );
///
/// let c = E::C(0, 0);
/// assert_tokens(&c, &[
/// Token::Enum { name: "E" },
/// Token::Str("C"),
/// Token::Seq { len: Some(2) },
/// Token::U8(0),
/// Token::U8(0),
/// Token::SeqEnd,
/// ]);
/// assert_tokens(
/// &c,
/// &[
/// Token::Enum { name: "E" },
/// Token::Str("C"),
/// Token::Seq { len: Some(2) },
/// Token::U8(0),
/// Token::U8(0),
/// Token::SeqEnd,
/// ],
/// );
///
/// let d = E::D { d: 0 };
/// assert_tokens(&d, &[
/// Token::Enum { name: "E" },
/// Token::Str("D"),
/// Token::Map { len: Some(1) },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::MapEnd,
/// ]);
/// assert_tokens(
/// &d,
/// &[
/// Token::Enum { name: "E" },
/// Token::Str("D"),
/// Token::Map { len: Some(1) },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::MapEnd,
/// ],
/// );
/// # }
/// ```
Enum { name: &'static str },
+2 -2
View File
@@ -12,10 +12,10 @@ unstable = ["serde/unstable"]
serde = { path = "../serde" }
[dev-dependencies]
automod = "1.0"
automod = "1.0.1"
fnv = "1.0"
rustversion = "1.0"
serde = { path = "../serde", features = ["rc", "derive"] }
serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" }
trybuild = { version = "1.0.66", features = ["diff"] }
+2 -1
View File
@@ -7,6 +7,7 @@ publish = false
[dependencies]
libc = { version = "0.2", default-features = false }
serde = { path = "../../serde", default-features = false, features = ["derive"] }
serde = { path = "../../serde", default-features = false }
serde_derive = { path = "../../serde_derive" }
[workspace]
+1 -1
View File
@@ -19,7 +19,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
//////////////////////////////////////////////////////////////////////////////
use serde::{Serialize, Deserialize};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Unit;
+1 -1
View File
@@ -1,4 +1,4 @@
use serde::Deserialize;
use serde_derive::Deserialize;
#[derive(Deserialize)]
pub struct Nested;
+11
View File
@@ -0,0 +1,11 @@
use serde_derive::Deserialize;
macro_rules! bug {
($serde_path:literal) => {
#[derive(Deserialize)]
#[serde(crate = $serde_path)]
pub struct Struct;
};
}
bug!("serde");
+5
View File
@@ -0,0 +1,5 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde()]
pub struct S;
+234 -3
View File
@@ -10,8 +10,9 @@
clippy::uninlined_format_args,
)]
use serde::de::{self, MapAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{self, Deserialize, Deserializer, IgnoredAny, MapAccess, Unexpected, Visitor};
use serde::ser::{Serialize, Serializer};
use serde_derive::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
@@ -1533,7 +1534,7 @@ fn test_invalid_length_enum() {
Token::TupleVariant {
name: "InvalidLengthEnum",
variant: "B",
len: 3,
len: 2,
},
Token::I32(1),
Token::TupleVariantEnd,
@@ -2317,6 +2318,53 @@ fn test_internally_tagged_enum_new_type_with_unit() {
);
}
#[test]
fn test_adjacently_tagged_enum_bytes() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A { a: i32 },
}
let data = Data::A { a: 0 };
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
assert_de_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Bytes(b"t"),
Token::Str("A"),
Token::Bytes(b"c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
}
#[test]
fn test_adjacently_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -2395,6 +2443,162 @@ fn test_untagged_enum_containing_flatten() {
);
}
#[test]
fn test_partially_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Exp {
Lambda(u32, Box<Exp>),
#[serde(untagged)]
App(Box<Exp>, Box<Exp>),
#[serde(untagged)]
Var(u32),
}
use Exp::*;
let data = Lambda(0, Box::new(App(Box::new(Var(0)), Box::new(Var(0)))));
assert_tokens(
&data,
&[
Token::TupleVariant {
name: "Exp",
variant: "Lambda",
len: 2,
},
Token::U32(0),
Token::Tuple { len: 2 },
Token::U32(0),
Token::U32(0),
Token::TupleEnd,
Token::TupleVariantEnd,
],
);
}
#[test]
fn test_partially_untagged_enum_generic() {
trait Trait<T> {
type Assoc;
type Assoc2;
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum E<A, B, C>
where
A: Trait<C, Assoc2 = B>,
{
A(A::Assoc),
#[serde(untagged)]
B(A::Assoc2),
}
impl<T> Trait<T> for () {
type Assoc = T;
type Assoc2 = bool;
}
type MyE = E<(), bool, u32>;
use E::*;
assert_tokens::<MyE>(&B(true), &[Token::Bool(true)]);
assert_tokens::<MyE>(
&A(5),
&[
Token::NewtypeVariant {
name: "E",
variant: "A",
},
Token::U32(5),
],
);
}
#[test]
fn test_partially_untagged_enum_desugared() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Test {
A(u32, u32),
B(u32),
#[serde(untagged)]
C(u32),
#[serde(untagged)]
D(u32, u32),
}
use Test::*;
mod desugared {
use super::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub(super) enum Test {
A(u32, u32),
B(u32),
}
}
use desugared::Test as TestTagged;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum TestUntagged {
Tagged(TestTagged),
C(u32),
D(u32, u32),
}
impl From<Test> for TestUntagged {
fn from(test: Test) -> Self {
match test {
A(x, y) => TestUntagged::Tagged(TestTagged::A(x, y)),
B(x) => TestUntagged::Tagged(TestTagged::B(x)),
C(x) => TestUntagged::C(x),
D(x, y) => TestUntagged::D(x, y),
}
}
}
fn assert_tokens_desugared(value: Test, tokens: &[Token]) {
assert_tokens(&value, tokens);
let desugared: TestUntagged = value.into();
assert_tokens(&desugared, tokens);
}
assert_tokens_desugared(
A(0, 1),
&[
Token::TupleVariant {
name: "Test",
variant: "A",
len: 2,
},
Token::U32(0),
Token::U32(1),
Token::TupleVariantEnd,
],
);
assert_tokens_desugared(
B(1),
&[
Token::NewtypeVariant {
name: "Test",
variant: "B",
},
Token::U32(1),
],
);
assert_tokens_desugared(C(2), &[Token::U32(2)]);
assert_tokens_desugared(
D(3, 5),
&[
Token::Tuple { len: 2 },
Token::U32(3),
Token::U32(5),
Token::TupleEnd,
],
);
}
#[test]
fn test_flatten_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -2494,6 +2698,31 @@ fn test_flatten_option() {
);
}
#[test]
fn test_flatten_ignored_any() {
#[derive(Deserialize, PartialEq, Debug)]
struct Outer {
#[serde(flatten)]
inner: IgnoredAny,
}
assert_de_tokens(
&Outer { inner: IgnoredAny },
&[Token::Map { len: None }, Token::MapEnd],
);
assert_de_tokens(
&Outer { inner: IgnoredAny },
&[
Token::Struct {
name: "DoNotMatter",
len: 0,
},
Token::StructEnd,
],
);
}
#[test]
fn test_transparent_struct() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -2737,7 +2966,9 @@ fn test_expecting_message() {
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
struct Struct {
#[allow(dead_code)]
question: String,
#[allow(dead_code)]
answer: u32,
}
+18 -14
View File
@@ -4,7 +4,9 @@
clippy::used_underscore_binding
)]
use serde::{Deserialize, Deserializer};
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
use serde::de::{Deserialize, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
use std::borrow::Cow;
@@ -130,20 +132,22 @@ fn test_cow() {
borrowed: Cow<'b, str>,
}
let tokens = &[
Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"),
Token::BorrowedStr("copied"),
Token::Str("borrowed"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
];
struct BorrowedStr(&'static str);
let mut de = serde_test::Deserializer::new(tokens);
let cows = Cows::deserialize(&mut de).unwrap();
impl<'de> IntoDeserializer<'de> for BorrowedStr {
type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>;
fn into_deserializer(self) -> Self::Deserializer {
BorrowedStrDeserializer::new(self.0)
}
}
let de = MapDeserializer::new(IntoIterator::into_iter([
("copied", BorrowedStr("copied")),
("borrowed", BorrowedStr("borrowed")),
]));
let cows = Cows::deserialize(de).unwrap();
match cows.copied {
Cow::Owned(ref s) if s == "copied" => {}
+34 -25
View File
@@ -14,6 +14,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::default::Default;
use std::ffi::{CStr, CString, OsString};
use std::fmt::Debug;
use std::iter;
use std::net;
use std::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
@@ -33,8 +34,8 @@ use std::time::{Duration, UNIX_EPOCH};
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer};
use serde::de::{Deserialize, DeserializeOwned, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Configure, Token};
#[macro_use]
@@ -45,6 +46,9 @@ mod macros;
#[derive(Copy, Clone, PartialEq, Debug, Deserialize)]
struct UnitStruct;
#[derive(Copy, Clone, PartialEq, Debug, Deserialize)]
struct GenericUnitStruct<const N: u8>;
#[derive(PartialEq, Debug, Deserialize)]
struct NewtypeStruct(i32);
@@ -199,12 +203,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
]
.into_iter()
.chain(ignorable_tokens.iter().copied())
.chain(vec![Token::MapEnd].into_iter())
.chain(iter::once(Token::MapEnd))
.collect();
let mut de = serde_test::Deserializer::new(&concated_tokens);
let base = IgnoreBase::deserialize(&mut de).unwrap();
assert_eq!(base, IgnoreBase { a: 1 });
let expected = IgnoreBase { a: 1 };
assert_de_tokens(&expected, &concated_tokens);
}
//////////////////////////////////////////////////////////////////////////
@@ -883,6 +886,17 @@ fn test_unit_struct() {
test(UnitStruct, &[Token::UnitStruct { name: "UnitStruct" }]);
}
#[test]
fn test_generic_unit_struct() {
test(GenericUnitStruct::<8>, &[Token::Unit]);
test(
GenericUnitStruct::<8>,
&[Token::UnitStruct {
name: "GenericUnitStruct",
}],
);
}
#[test]
fn test_newtype_struct() {
test(
@@ -2245,39 +2259,34 @@ fn test_cstr() {
#[test]
fn test_atomics() {
fn test<L, A, T>(load: L, val: T, token: Token)
fn test<L, A, T>(load: L, val: T)
where
L: Fn(&A, Ordering) -> T,
A: DeserializeOwned,
T: PartialEq + Debug,
T: PartialEq + Debug + Copy + for<'de> IntoDeserializer<'de>,
{
let tokens = &[token];
let mut de = serde_test::Deserializer::new(tokens);
match A::deserialize(&mut de) {
match A::deserialize(val.into_deserializer()) {
Ok(v) => {
let loaded = load(&v, Ordering::Relaxed);
assert_eq!(val, loaded);
}
Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
}
}
test(AtomicBool::load, true, Token::Bool(true));
test(AtomicI8::load, -127, Token::I8(-127i8));
test(AtomicI16::load, -510, Token::I16(-510i16));
test(AtomicI32::load, -131072, Token::I32(-131072i32));
test(AtomicIsize::load, -131072isize, Token::I32(-131072));
test(AtomicU8::load, 127, Token::U8(127u8));
test(AtomicU16::load, 510u16, Token::U16(510u16));
test(AtomicU32::load, 131072u32, Token::U32(131072u32));
test(AtomicUsize::load, 131072usize, Token::U32(131072));
test(AtomicBool::load, true);
test(AtomicI8::load, -127i8);
test(AtomicI16::load, -510i16);
test(AtomicI32::load, -131072i32);
test(AtomicIsize::load, -131072isize);
test(AtomicU8::load, 127u8);
test(AtomicU16::load, 510u16);
test(AtomicU32::load, 131072u32);
test(AtomicUsize::load, 131072usize);
#[cfg(target_arch = "x86_64")]
{
test(AtomicI64::load, -8589934592, Token::I64(-8589934592));
test(AtomicU64::load, 8589934592u64, Token::U64(8589934592));
test(AtomicI64::load, -8589934592i64);
test(AtomicU64::load, 8589934592u64);
}
}
+2 -2
View File
@@ -5,8 +5,8 @@
)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use serde::de::IntoDeserializer;
use serde::Deserialize;
use serde::de::{Deserialize, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens_error, Token};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::{CStr, CString};
+14 -4
View File
@@ -20,8 +20,9 @@
clippy::type_repetition_in_bounds
)]
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::marker::PhantomData;
@@ -404,7 +405,7 @@ fn test_gen() {
}
mod vis {
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
pub struct S;
@@ -636,7 +637,7 @@ fn test_gen() {
mod restricted {
mod inner {
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Restricted {
@@ -662,6 +663,7 @@ fn test_gen() {
#[derive(Deserialize)]
struct ImplicitlyBorrowedOption<'a> {
#[allow(dead_code)]
option: std::option::Option<&'a str>,
}
@@ -692,7 +694,9 @@ fn test_gen() {
#[derive(Deserialize)]
struct RelObject<'a> {
#[allow(dead_code)]
ty: &'a str,
#[allow(dead_code)]
id: String,
}
@@ -736,6 +740,7 @@ fn test_gen() {
($field:ty) => {
#[derive(Deserialize)]
struct MacroRules<'a> {
#[allow(dead_code)]
field: $field,
}
};
@@ -752,6 +757,7 @@ fn test_gen() {
#[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")]
#[allow(dead_code)]
f: mac!(Cow<'a, str>),
}
@@ -760,6 +766,10 @@ fn test_gen() {
#[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
struct GenericUnitStruct<const N: usize>;
}
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -2,7 +2,7 @@
#![allow(clippy::derive_partial_eq_without_eq)]
use serde::Deserialize;
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Token};
#[test]
+4 -2
View File
@@ -2,9 +2,11 @@
use serde::de::value::{Error, MapDeserializer, SeqDeserializer};
use serde::de::{
DeserializeSeed, EnumAccess, IgnoredAny, IntoDeserializer, VariantAccess, Visitor,
Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, IntoDeserializer,
VariantAccess, Visitor,
};
use serde::{forward_to_deserialize_any, Deserialize, Deserializer};
use serde::forward_to_deserialize_any;
use serde_derive::Deserialize;
#[derive(PartialEq, Debug, Deserialize)]
enum Target {
+59 -1
View File
@@ -8,7 +8,7 @@
mod bytes;
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token,
};
@@ -1267,6 +1267,38 @@ fn test_adjacently_tagged_enum() {
Token::StructEnd,
],
);
// integer field keys
assert_de_tokens(
&AdjacentlyTagged::Newtype::<u8>(1),
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::U64(1), // content field
Token::U8(1),
Token::U64(0), // tag field
Token::Str("Newtype"),
Token::StructEnd,
],
);
// byte-array field keys
assert_de_tokens(
&AdjacentlyTagged::Newtype::<u8>(1),
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Bytes(b"c"),
Token::U8(1),
Token::Bytes(b"t"),
Token::Str("Newtype"),
Token::StructEnd,
],
);
}
#[test]
@@ -1330,6 +1362,32 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
],
r#"invalid value: string "h", expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::U64(0), // tag field
Token::Str("Unit"),
Token::U64(3),
],
r#"invalid value: integer `3`, expected "t" or "c""#,
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 2,
},
Token::Bytes(b"c"),
Token::Unit,
Token::Bytes(b"h"),
],
r#"invalid value: byte array, expected "t" or "c""#,
);
}
#[test]
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_field_names)]
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
mod remote {
pub struct Unit;
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(clippy::used_underscore_binding)]
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
#[test]
fn test_self() {
+1 -1
View File
@@ -22,7 +22,7 @@ use std::str;
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher;
use serde::Serialize;
use serde_derive::Serialize;
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
#[macro_use]
+1 -1
View File
@@ -5,7 +5,7 @@
#[test]
fn test_gen_custom_serde() {
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
#[serde(crate = "fake_serde")]
struct Foo;
+2 -2
View File
@@ -1,8 +1,8 @@
#![allow(clippy::derive_partial_eq_without_eq, clippy::similar_names)]
use serde::de::value::{self, MapAccessDeserializer};
use serde::de::{IntoDeserializer, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use serde::de::{Deserialize, Deserializer, IntoDeserializer, MapAccess, Visitor};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Token};
use std::fmt;
@@ -0,0 +1,10 @@
use serde_derive::Serialize;
#[derive(Serialize)]
enum E {
#[serde(untagged)]
A(u8),
B(String),
}
fn main() {}
@@ -0,0 +1,5 @@
error: all variants with the #[serde(untagged)] attribute must be placed at the end of the enum
--> tests/ui/enum-representation/partially_tagged_wrong_order.rs:6:5
|
6 | A(u8),
| ^

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