Compare commits

...

94 Commits

Author SHA1 Message Date
David Tolnay 2b92c80cc1 Release 1.0.129 2021-08-23 15:01:24 -07:00
David Tolnay c1c0ede452 Merge pull request #2080 from dtolnay/packeddrop
Support packed remote struct without destructuring
2021-08-23 15:00:50 -07:00
David Tolnay 4a66c5f33d Support packed remote struct without destructuring 2021-08-23 14:38:33 -07:00
David Tolnay 714c8a5586 Add test of packed struct that cannot be destructured
Currently fails:

    error[E0509]: cannot move out of type `RemotePackedNonCopyDef`, which implements the `Drop` trait
       --> test_suite/tests/test_gen.rs:876:10
        |
    876 | #[derive(Deserialize)]
        |          ^^^^^^^^^^^
        |          |
        |          cannot move out of here
        |          data moved here
        |          move occurs because `__v1` has type `std::string::String`, which does not implement the `Copy` trait
        |
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2021-08-23 14:38:33 -07:00
David Tolnay dc0c0dcba1 Merge pull request #2079 from dtolnay/packedremote
Fix unaligned reference warnings on packed remote def
2021-08-23 14:38:21 -07:00
David Tolnay 54102ee7d0 Avoid generating ref patterns for fields of packed remote struct 2021-08-23 10:18:28 -07:00
David Tolnay 14accf7518 Add test of remote with a packed struct
Currently fails to build:

    error: reference to packed field is unaligned
       --> test_suite/tests/test_gen.rs:858:10
        |
    858 | #[derive(Serialize, Deserialize)]
        |          ^^^^^^^^^
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[deny(unaligned_references)]` implied by `#[deny(warnings)]`
        = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
        = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
        = note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)

    error: reference to packed field is unaligned
       --> test_suite/tests/test_gen.rs:858:21
        |
    858 | #[derive(Serialize, Deserialize)]
        |                     ^^^^^^^^^^^
        |
        = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
        = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2021-08-23 10:18:05 -07:00
David Tolnay 55fdbea20b Merge pull request #2077 from dtolnay/tryfold
Use try_fold in default implementation of collect_seq, collect_map
2021-08-21 14:08:20 -07:00
David Tolnay 75d8902371 Use try_fold in default implementation of collect_seq, collect_map 2021-08-21 14:00:51 -07:00
David Tolnay 9451ea8df1 Format PR 1992 with rustfmt 2021-08-21 12:49:58 -07:00
David Tolnay c1ce03b3dd Merge pull request 1992 from Mingun/unnecessary-deserialize-with 2021-08-21 12:49:39 -07:00
David Tolnay a587eb8953 Release 1.0.128 2021-08-21 10:39:32 -07:00
Oli Scherer 990f7eb6c1 Merge pull request #2076 from Manishearth/emscripten-i128
Enable 128-bit integers on emscripten post Rust 1.40
2021-08-21 19:19:30 +02:00
Manish Goregaokar 082e18f9a1 Rust supports i128/u128 on emscripten post Rust 1.40 2021-08-20 21:57:06 -07:00
David Tolnay f309485787 Ignore buggy collapsible_match clippy lint
https://github.com/rust-lang/rust-clippy/issues/7575
2021-08-16 19:32:10 -07:00
David Tolnay e2f85681fe Release 1.0.127 2021-07-30 20:59:13 -07:00
David Tolnay 8b840c3030 Resolve semicolon_in_expressions_from_macros warning in serde_test
warning: trailing semicolon in macro used in expression position
       --> serde_test/src/ser.rs:44:10
        |
    44  |         );
        |          ^
    ...
    152 |             Some(&Token::BorrowedStr(_)) => assert_next_token!(self, BorrowedStr(v)),
        |                                             ---------------------------------------- in this macro invocation
        |
        = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
        = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
        = note: this warning originates in the macro `assert_next_token` (in Nightly builds, run with -Z macro-backtrace for more info)

    warning: trailing semicolon in macro used in expression position
       --> serde_test/src/ser.rs:36:76
        |
    36  |         assert_next_token!($ser, stringify!($actual), Token::$actual, true);
        |                                                                            ^
    ...
    386 |             Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd),
        |                                       --------------------------------------------- in this macro invocation
        |
        = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
        = note: this warning originates in the macro `assert_next_token` (in Nightly builds, run with -Z macro-backtrace for more info)
2021-07-30 20:58:07 -07:00
David Tolnay 9c39115f82 Ignore buggy nonstandard_macro_braces clippy lint
Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422

    error: use of irregular braces for `format_args!` macro
       --> test_suite/tests/test_gen.rs:528:25
        |
    528 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^
        |
        = note: `-D clippy::nonstandard-macro-braces` implied by `-D clippy::all`
    help: consider writing `Deserialize`
       --> test_suite/tests/test_gen.rs:528:25
        |
    528 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

    error: use of irregular braces for `format_args!` macro
        --> test_suite/tests/test_annotations.rs:1791:43
         |
    1791 |     #[derive(Debug, PartialEq, Serialize, Deserialize)]
         |                                           ^^^^^^^^^^^
         |
         = note: `-D clippy::nonstandard-macro-braces` implied by `-D clippy::all`
    help: consider writing `Deserialize`
        --> test_suite/tests/test_annotations.rs:1791:43
         |
    1791 |     #[derive(Debug, PartialEq, Serialize, Deserialize)]
         |                                           ^^^^^^^^^^^
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
         = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
2021-07-02 20:58:04 -07:00
David Tolnay 89342af71e Merge pull request #2047 from jsoref/spelling
spelling: implicitly
2021-06-24 22:25:58 -07:00
Josh Soref 3c5e2d11f6 spelling: implicitly
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2021-06-25 00:43:23 -04:00
David Tolnay 3805c037a8 Merge pull request #2040 from dtolnay/test
Fix outdated test instructions in CONTRIBUTING.md
2021-06-12 13:43:30 -07:00
David Tolnay 7045fee260 Fix outdated test instructions in CONTRIBUTING.md 2021-06-12 13:38:40 -07:00
David Tolnay 9d81532e41 Merge pull request #2039 from dtolnay/test
Update documented test command for the serde directory
2021-06-12 13:38:34 -07:00
David Tolnay 5e47432ef0 Update documented test command for the serde directory 2021-06-12 13:34:45 -07:00
Mingun e0fc46783d Add test with generic deserialize_with function 2021-06-12 18:47:08 +05:00
Mingun ca772a14f9 Get rid of useless DeserializeWith wrapper 2021-06-12 18:38:03 +05:00
David Tolnay 7b840897a9 Resolve needless_borrow clippy lints
error: this expression borrows a reference (`&syn::Type`) that is immediately dereferenced by the compiler
       --> serde_derive/src/internals/check.rs:399:37
        |
    399 |     if let Type::Path(ty) = ungroup(&field.ty) {
        |                                     ^^^^^^^^^ help: change this to: `field.ty`
        |
    note: the lint level is defined here
       --> serde_derive/src/lib.rs:18:9
        |
    18  | #![deny(clippy::all, clippy::pedantic)]
        |         ^^^^^^^^^^^
        = note: `#[deny(clippy::needless_borrow)]` implied by `#[deny(clippy::all)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&str`) that is immediately dereferenced by the compiler
       --> serde_derive/src/de.rs:478:52
        |
    478 |         &type_path, params, fields, false, cattrs, &expecting,
        |                                                    ^^^^^^^^^^ help: change this to: `expecting`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&str`) that is immediately dereferenced by the compiler
       --> serde_derive/src/de.rs:564:76
        |
    564 |     let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
        |                                                                            ^^^^^^^^^^ help: change this to: `expecting`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&str`) that is immediately dereferenced by the compiler
       --> serde_derive/src/de.rs:925:51
        |
    925 |         &type_path, params, fields, true, cattrs, &expecting,
        |                                                   ^^^^^^^^^^ help: change this to: `expecting`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&str`) that is immediately dereferenced by the compiler
        --> serde_derive/src/de.rs:1066:76
         |
    1066 |     let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
         |                                                                            ^^^^^^^^^^ help: change this to: `expecting`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&proc_macro2::TokenStream`) that is immediately dereferenced by the compiler
        --> serde_derive/src/de.rs:2288:80
         |
    2288 |         let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(&fallthrough_arm);
         |                                                                                ^^^^^^^^^^^^^^^^ help: change this to: `fallthrough_arm`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

    error: this expression borrows a reference (`&syn::Member`) that is immediately dereferenced by the compiler
        --> serde_derive/src/ser.rs:1102:43
         |
    1102 |                 get_member(params, field, &member)
         |                                           ^^^^^^^ help: change this to: `member`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
2021-06-04 20:58:23 -07:00
David Tolnay 967795414b Resolve semicolon_if_nothing_returned clippy lints
error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/attr.rs:559:25
        |
    559 |                         serde_path.set(&m.path, path)
        |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `serde_path.set(&m.path, path);`
        |
    note: the lint level is defined here
       --> serde_derive/src/lib.rs:18:22
        |
    18  | #![deny(clippy::all, clippy::pedantic)]
        |                      ^^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::semicolon_if_nothing_returned)]` implied by `#[deny(clippy::pedantic)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned

    error: consider adding a `;` to the last statement for consistent formatting
        --> serde_derive/src/internals/attr.rs:1612:9
         |
    1612 |         cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()));`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned

    error: consider adding a `;` to the last statement for consistent formatting
        --> serde_derive/src/internals/attr.rs:1623:9
         |
    1623 |         cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()));`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned

    error: consider adding a `;` to the last statement for consistent formatting
        --> serde_derive/src/internals/attr.rs:1649:9
         |
    1649 | /         cx.error_spanned_by(
    1650 | |             lit,
    1651 | |             format!("failed to parse type: {} = {:?}", attr_name, string.value()),
    1652 | |         )
         | |_________^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
    help: add a `;` here
         |
    1649 |         cx.error_spanned_by(
    1650 |             lit,
    1651 |             format!("failed to parse type: {} = {:?}", attr_name, string.value()),
    1652 |         );
         |

    error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/check.rs:260:9
        |
    260 | /         cx.error_spanned_by(
    261 | |             cont.original,
    262 | |             format!("variant field name `{}` conflicts with internal tag", tag),
    263 | |         )
        | |_________^
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
    help: add a `;` here
        |
    260 |         cx.error_spanned_by(
    261 |             cont.original,
    262 |             format!("variant field name `{}` conflicts with internal tag", tag),
    263 |         );
        |

    error: consider adding a `;` to the last statement for consistent formatting
        --> serde_derive/src/de.rs:2090:9
         |
    2090 |         flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `flat_fields.extend(aliases.iter().map(|alias| (alias, ident)));`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
2021-06-04 20:55:22 -07:00
David Tolnay 985725f820 Resolve while_let_on_iterator clippy lint
error: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2835:9
         |
    2835 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in &mut self.iter`
         |
    note: the lint level is defined here
        --> serde/src/lib.rs:97:44
         |
    97   | #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
         |                                            ^^^^^^
         = note: `#[deny(clippy::while_let_on_iterator)]` implied by `#[deny(clippy::all)]`
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator

    error: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2937:9
         |
    2937 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in &mut self.iter`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
2021-05-22 20:29:34 -07:00
David Tolnay 0c303d85d7 Merge pull request #2027 from striezel-stash/fix-typos
fix some typos
2021-05-15 10:14:13 -07:00
Dirk Stolle f68e9e901e fix some typos 2021-05-15 16:18:05 +02:00
David Tolnay 1094e2d334 Update ui test suite to nightly-2021-05-14 2021-05-13 19:16:07 -07:00
David Tolnay d9c338ec4a Release 1.0.126 2021-05-12 10:18:26 -07:00
David Tolnay 699bf3a75d Merge pull request #2026 from hyd-dev/warning
Allow only `unused_extern_crates` instead of the whole `rust_2018_idioms` lint group in `serde_derive`-generated code
2021-05-12 10:16:47 -07:00
hyd-dev dd29825217 Allow only unused_extern_crates instead of the whole rust_2018_idioms lint group in serde_derive-generated code 2021-05-12 18:29:45 +08:00
David Tolnay 6366f17da7 Ignore clone_instead_of_copied pedantic clippy lint
Iterator::copied was introduced in Rust 1.35, whereas serde_test
currently supports a minimum compiler version of 1.13.

    error: used `cloned` where `copied` could be used instead
       --> serde_test/src/de.rs:49:29
        |
    49  |         self.tokens.first().cloned()
        |                             ^^^^^^ help: try: `copied`
        |
    note: the lint level is defined here
       --> serde_test/src/lib.rs:149:52
        |
    149 | #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
        |                                                    ^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::cloned_instead_of_copied)]` implied by `#[deny(clippy::pedantic)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied
2021-04-24 19:26:19 -07:00
David Tolnay 1120e5af4a Remove suppression of removed clippy lint
warning: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
      --> serde_derive/src/lib.rs:42:5
       |
    42 |     clippy::filter_map,
       |     ^^^^^^^^^^^^^^^^^^
       |
       = note: `#[warn(renamed_and_removed_lints)]` on by default

    warning: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
      --> serde_derive/src/lib.rs:42:5
       |
    42 |     clippy::filter_map,
       |     ^^^^^^^^^^^^^^^^^^
2021-04-24 19:23:56 -07:00
David Tolnay 1093f7e232 Resolve flat_map_option pedantic clippy lint
error: used `flat_map` where `filter_map` could be used instead
      --> serde_derive/src/bound.rs:52:10
       |
    52 |         .flat_map(|field| from_field(&field.attrs))
       |          ^^^^^^^^ help: try: `filter_map`
       |
    note: the lint level is defined here
      --> serde_derive/src/lib.rs:18:22
       |
    18 | #![deny(clippy::all, clippy::pedantic)]
       |                      ^^^^^^^^^^^^^^^^
       = note: `#[deny(clippy::flat_map_option)]` implied by `#[deny(clippy::pedantic)]`
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option

    error: used `flat_map` where `filter_map` could be used instead
      --> serde_derive/src/bound.rs:74:10
       |
    74 |         .flat_map(|variant| from_variant(&variant.attrs))
       |          ^^^^^^^^ help: try: `filter_map`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
2021-04-24 19:23:21 -07:00
David Tolnay 2ea132b8c4 Merge pull request #2018 from dtolnay/nonascii
Remove non_ascii_idents feature gate from test suite
2021-04-19 20:24:51 -07:00
David Tolnay 2ebc771b88 Remove non_ascii_idents feature gate from test suite
error: the feature `non_ascii_idents` has been stable since 1.53.0 and no longer requires an attribute to enable
     --> test_suite/tests/test_gen.rs:6:43
      |
    6 | #![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
      |                                           ^^^^^^^^^^^^^^^^
      |
    note: the lint level is defined here
     --> test_suite/tests/test_gen.rs:5:9
      |
    5 | #![deny(warnings)]
      |         ^^^^^^^^
      = note: `#[deny(stable_features)]` implied by `#[deny(warnings)]`
2021-04-19 19:55:12 -07:00
David Tolnay c17c4eef18 Unify stable and beta CI workflow 2021-04-19 19:54:56 -07:00
David Tolnay 7aa4950504 Release serde_derive_internals 0.26.0 2021-04-09 14:23:13 -07:00
David Tolnay 47015a2727 Merge pull request #2015 from dtolnay/symlink
Build using relative path in repo if Windows lost the symlink
2021-04-09 14:20:55 -07:00
David Tolnay dc4c31eb50 Build using relative path in repo if Windows lost symlink 2021-04-09 14:16:17 -07:00
David Tolnay b53ebef438 Resolve safe_packed_borrows lint renamed to unaligned_references
warning: lint `safe_packed_borrows` has been renamed to `unaligned_references`
        --> test_suite/tests/test_macros.rs:1926:8
         |
    1926 | #[deny(safe_packed_borrows)]
         |        ^^^^^^^^^^^^^^^^^^^ help: use the new name: `unaligned_references`
         |
         = note: `#[warn(renamed_and_removed_lints)]` on by default
2021-04-08 20:08:42 -07:00
David Tolnay 6c3bf7a2fc Ignore poor suggestion from branches_sharing_code lint
https://github.com/rust-lang/rust-clippy/issues/7054

    error: all if blocks contain the same code at the end
        --> serde_derive/src/de.rs:2160:5
         |
    2160 | /         &fallthrough_arm_tokens
    2161 | |     };
         | |_____^
         |
    note: the lint level is defined here
        --> serde_derive/src/lib.rs:18:9
         |
    18   | #![deny(clippy::all, clippy::pedantic)]
         |         ^^^^^^^^^^^
         = note: `#[deny(clippy::branches_sharing_code)]` implied by `#[deny(clippy::all)]`
         = note: The end suggestion probably needs some adjustments to use the expression result correctly
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
    help: consider moving the end statements out like this
         |
    2160 |     }
    2161 |     &fallthrough_arm_tokens;
         |
2021-04-08 20:08:42 -07:00
David Tolnay ce0844b9ec Suppress match_wildcard_for_single_variants clippy false positive
https://github.com/rust-lang/rust-clippy/issues/6984

    error: wildcard matches only a single variant and will also match any future added variants
        --> serde_derive/src/internals/attr.rs:1918:9
         |
    1918 |         _ => {}
         |         ^ help: try this: `syn::Type::__TestExhaustive(_)`
         |
    note: the lint level is defined here
        --> serde_derive/src/lib.rs:18:22
         |
    18   | #![deny(clippy::all, clippy::pedantic)]
         |                      ^^^^^^^^^^^^^^^^
         = note: `#[deny(clippy::match_wildcard_for_single_variants)]` implied by `#[deny(clippy::pedantic)]`
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

    error: wildcard matches only a single variant and will also match any future added variants
       --> serde_derive/src/internals/receiver.rs:153:13
        |
    153 |             _ => {}
        |             ^ help: try this: `Type::__TestExhaustive(_)`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

    error: wildcard matches only a single variant and will also match any future added variants
       --> serde_derive/src/bound.rs:190:17
        |
    190 |                 _ => {}
        |                 ^ help: try this: `syn::Type::__TestExhaustive(_)`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
2021-03-26 23:30:15 -04:00
David Tolnay e9270e59f0 Release 1.0.125 2021-03-22 16:15:57 -07:00
David Tolnay 72060b779a Extend test_format_u8 to include u8::MAX
This is equivalent to looping 0..=u8::MAX, except that `..=` syntax is
not supported on old rustc and `...` syntax is not supported on new
rustc, so loop it is.
2021-03-22 16:09:33 -07:00
David Tolnay 1bb23ad9d1 Remove format_u8 when not used by Ipv4Addr impl 2021-03-22 16:00:58 -07:00
David Tolnay 9be4c9654a Merge pull request 2001 from saethlin/optimize-ipaddr 2021-03-22 16:00:11 -07:00
Ben Kimock 4114e90bac Fix off-by-one mistake, explain the offset 2021-03-22 18:39:24 -04:00
Ben Kimock 8bb07b0743 skip UTF8 checking and initialize with b'.' 2021-03-22 18:15:50 -04:00
Ben Kimock ba8c1d63c8 use the algorithm from itoa 2021-03-16 17:33:42 -04:00
Ben Kimock 857a805993 Faster Ipv4 serialization prototype 2021-03-16 10:41:13 -04:00
David Tolnay 5a8dcac2ed Release 1.0.124 2021-03-05 19:55:40 -08:00
David Tolnay 697b082e90 Touch up PR 1997 2021-03-05 19:48:40 -08:00
David Tolnay d91075c8d5 Merge pull request #1997 from cyang1/systemtime-panics
Prevent various panics when deserializing malformed SystemTime
2021-03-05 18:35:48 -08:00
Cary Yang 4118cec731 Prevent various panics when deserializing malformed SystemTime 2021-03-05 17:52:51 -08:00
David Tolnay c261015325 Ignore incorrect suggestion from manual_map lint
https://github.com/rust-lang/rust-clippy/issues/6797

    error[E0382]: use of partially moved value: `self`
       --> serde_derive/src/internals/attr.rs:71:24
        |
    71  |         self.value.map(|value| (self.tokens, value))
        |                    ----^^^^^^^----------------------
        |                    |   |        |
        |                    |   |        use occurs due to use in closure
        |                    |   value used here after partial move
        |                    `self.value` partially moved due to this method call
        |
    note: this function takes ownership of the receiver `self`, which moves `self.value`
       --> /home/david/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:485:38
        |
    485 |     pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
        |                                      ^^^^
        = note: partial move occurs because `self.value` has type `std::option::Option<T>`, which does not implement the `Copy` trait
2021-02-25 20:53:45 -08:00
David Tolnay 6b5e5a83d0 Ignore let_underscore_drop pedantic clippy lint 2021-02-18 19:31:39 -08:00
David Tolnay bc6b2b1dee Make json5 description capitalization consistent with other links 2021-02-10 23:13:12 -08:00
David Tolnay beb21cb640 Ignore new missing_panics_doc pedantic clippy lint 2021-02-03 20:07:44 -08:00
David Tolnay 7cfebbcd72 Merge pull request #1974 from Mingun/new-internally-tagged-tests
New internally tagged tests
2021-02-02 15:23:10 -08:00
Mingun b60c03ec3f Extend test_internally_tagged_newtype_variant_containing_unit_struct to cover structs and seqs 2021-02-02 09:00:04 +05:00
Mingun 3257851192 Extend test_internally_tagged_struct_variant_containing_unit_variant to cover maps and seqs 2021-02-02 08:59:59 +05:00
David Tolnay 9a84622c56 Merge pull request #1971 from arthurprs/untagged-enum-fix-pr
Allow floats to be deserialized from ints in untagged unions (part 2)
2021-01-26 14:41:56 -08:00
Arthur Silva de8ac1c0be Allow floats to be deserialized from ints in untagged unions 2021-01-26 17:47:20 +01:00
David Tolnay 3d6c4149b1 Release 1.0.123 2021-01-25 13:43:11 -08:00
David Tolnay 29cdf888c0 Merge pull request #1970 from serde-rs/self
Support `Self` inside fields that use serialize_with
2021-01-25 13:42:35 -08:00
David Tolnay 2ba97394fb Substitute Self in output of Serialize derive 2021-01-25 13:34:09 -08:00
David Tolnay 6699b0bc40 Add regression test for issue 1969 2021-01-25 13:34:08 -08:00
David Tolnay b054ea4105 Ignore some pedantic lints in serde_derive_internals from PR 1830
error: item name ends with its containing module's name
      --> serde_derive_internals/src/receiver.rs:11:1
       |
    11 | / pub fn replace_receiver(input: &mut DeriveInput) {
    12 | |     let self_ty = {
    13 | |         let ident = &input.ident;
    14 | |         let ty_generics = input.generics.split_for_impl().1;
    ...  |
    19 | |     visitor.visit_data_mut(&mut input.data);
    20 | | }
       | |_^
       |
    note: the lint level is defined here
      --> serde_derive_internals/lib.rs:3:22
       |
    3  | #![deny(clippy::all, clippy::pedantic)]
       |                      ^^^^^^^^^^^^^^^^
       = note: `#[deny(clippy::module_name_repetitions)]` implied by `#[deny(clippy::pedantic)]`
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions

    error: binding's name is too similar to existing binding
      --> serde_derive_internals/src/receiver.rs:31:29
       |
    31 |     fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
       |                             ^^^^^
       |
    note: the lint level is defined here
      --> serde_derive_internals/lib.rs:3:22
       |
    3  | #![deny(clippy::all, clippy::pedantic)]
       |                      ^^^^^^^^^^^^^^^^
       = note: `#[deny(clippy::similar_names)]` implied by `#[deny(clippy::pedantic)]`
    note: existing binding defined here
      --> serde_derive_internals/src/receiver.rs:31:23
       |
    31 |     fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
       |                       ^^^^
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#similar_names

    error: unused `self` argument
       --> serde_derive_internals/src/receiver.rs:286:24
        |
    286 |     fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
        |                        ^^^^^^^^^
        |
    note: the lint level is defined here
       --> serde_derive_internals/lib.rs:3:22
        |
    3   | #![deny(clippy::all, clippy::pedantic)]
        |                      ^^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::unused_self)]` implied by `#[deny(clippy::pedantic)]`
        = help: consider refactoring to a associated function
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
2021-01-25 00:03:03 -08:00
David Tolnay e5efb6ad93 Remove dependency on syn/visit-mut feature 2021-01-24 23:56:57 -08:00
David Tolnay 1f423580a5 Deduplicate token stream respanner 2021-01-24 23:06:08 -08:00
David Tolnay 033114a4ae Touch up PR 1830 2021-01-24 23:06:07 -08:00
David Tolnay 7cec99c7fd Pare down PR 1830
Unlike expr macros, macros in type position in a derive input are rare
enough that it's not worth supporting for an issue that has such an easy
workaround (just replace `Self` in the macro input with your type name).
2021-01-24 23:06:06 -08:00
David Tolnay 6c5bf701be Merge pull request 1830 from taiki-e/self 2021-01-24 23:05:51 -08:00
David Tolnay 6e800ff826 Test exhaustiveness of type match in collect_lifetimes 2021-01-24 23:04:01 -08:00
David Tolnay 68bda7a004 Include serde crate in 1.31 CI job 2021-01-24 20:42:20 -08:00
David Tolnay dfeaf77bb2 Merge pull request #1966 from serde-rs/private
Omit derive helpers in versions older than serde_derive msrv
2021-01-24 20:40:06 -08:00
David Tolnay b0cc213e57 Omit derive helpers in versions older than serde_derive msrv 2021-01-24 20:26:56 -08:00
David Tolnay 74ca06662e Omit size_hint::cautious when not allocating 2021-01-24 20:24:03 -08:00
David Tolnay 38edb473de Move size_hint module out of private::de 2021-01-24 20:23:07 -08:00
David Tolnay 1c03647656 Move InPlaceSeed out of private mod 2021-01-24 20:23:06 -08:00
David Tolnay aeee73fe92 Merge pull request #1831 from taiki-e/borrow-macro
Collect lifetimes inside macro invocations
2021-01-24 19:08:20 -08:00
David Tolnay 1a3ef39040 Merge pull request #1842 from Timmmm/fix2
Allow floats to be deserialized from ints in tagged unions
2021-01-24 18:48:46 -08:00
David Tolnay deaf600af7 Merge pull request #1965 from serde-rs/int
Reduce post-macro-expansion code in integer deserialize impls
2021-01-24 18:43:36 -08:00
David Tolnay 48556a4c7f Reduce post-macro-expansion code in integer deserialize impls 2021-01-24 18:26:50 -08:00
David Tolnay d88a4748f7 Remove unused $ty arg from internal impl_deserialize_num macro 2021-01-24 17:06:36 -08:00
Taiki Endo e81f54fbc8 Make AST borrow checker happy 2021-01-24 15:23:54 +09:00
Taiki Endo c67017d466 Fix handling of Self keyword in type definition 2021-01-24 15:23:51 +09:00
Taiki Endo a227a87865 Collect lifetimes inside macro invocations 2020-10-24 05:29:47 +09:00
Tim Hutt 010444dfa4 Allow floats to be deserialized from ints in tagged unions 2020-06-22 16:31:13 +01:00
55 changed files with 1287 additions and 661 deletions
+10 -11
View File
@@ -23,25 +23,22 @@ jobs:
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
stable:
name: Rust stable
name: Rust ${{matrix.rust}}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust: [stable, beta]
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
- run: cd serde && cargo build --features rc
- run: cd serde && cargo build --no-default-features
- run: cd serde_test && cargo build
- run: cd serde_test && cargo test --features serde/derive,serde/rc
beta:
name: Rust beta
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@beta
- run: cd serde && cargo build --features rc
- run: cd test_suite && cargo test
nightly:
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
runs-on: ${{matrix.os}}-latest
@@ -115,6 +112,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@1.31.0
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
alloc:
+4 -10
View File
@@ -31,25 +31,19 @@ tests for you.
```sh
# Test all the example code in Serde documentation
cargo test
```
##### In the [`test_suite/deps`] directory
```sh
# This is a prerequisite for running the full test suite
cargo clean && cargo update && cargo build
cargo test --features derive
```
##### In the [`test_suite`] directory
```sh
# Run the full test suite, including tests of unstable functionality
cargo test --features unstable
cargo +nightly test --features unstable
```
Note that this test suite currently only supports running on a nightly compiler.
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
[`test_suite/deps`]: https://github.com/serde-rs/serde/tree/master/test_suite/deps
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
## Conduct
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.122" # remember to update html_root_url and serde_derive dependency
version = "1.0.129" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "A generic serialization/deserialization framework"
@@ -14,7 +14,7 @@ include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APAC
build = "build.rs"
[dependencies]
serde_derive = { version = "=1.0.122", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.129", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
+15 -4
View File
@@ -53,16 +53,20 @@ fn main() {
// 128-bit integers stabilized in Rust 1.26:
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
//
// Disabled on Emscripten targets as Emscripten doesn't
// currently support integers larger than 64 bits.
if minor >= 26 && !emscripten {
// Disabled on Emscripten targets before Rust 1.40 since
// Emscripten did not support 128-bit integers until Rust 1.40
// (https://github.com/rust-lang/rust/pull/65251)
if minor >= 26 && (!emscripten || minor >= 40) {
println!("cargo:rustc-cfg=integer128");
}
// Inclusive ranges methods stabilized in Rust 1.27:
// https://github.com/rust-lang/rust/pull/50758
// Also Iterator::try_for_each:
// https://blog.rust-lang.org/2018/06/21/Rust-1.27.html#library-stabilizations
if minor >= 27 {
println!("cargo:rustc-cfg=range_inclusive");
println!("cargo:rustc-cfg=iterator_try_fold");
}
// Non-zero integers stabilized in Rust 1.28:
@@ -71,12 +75,19 @@ fn main() {
println!("cargo:rustc-cfg=num_nonzero");
}
// TryFrom, Atomic types, and non-zero signed integers stabilized in Rust 1.34:
// Current minimum supported version of serde_derive crate is Rust 1.31.
if minor >= 31 {
println!("cargo:rustc-cfg=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
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
if minor >= 34 {
println!("cargo:rustc-cfg=core_try_from");
println!("cargo:rustc-cfg=num_nonzero_signed");
println!("cargo:rustc-cfg=systemtime_checked_add");
// Whitelist of archs that support std::sync::atomic module. Ideally we
// would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
-260
View File
@@ -1,260 +0,0 @@
use lib::*;
macro_rules! int_to_int {
($dst:ident, $n:ident) => {
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
Some($n as $dst)
} else {
None
}
};
}
macro_rules! int_to_uint {
($dst:ident, $n:ident) => {
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
}
};
}
macro_rules! uint_to {
($dst:ident, $n:ident) => {
if $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
}
};
}
pub trait FromPrimitive: Sized {
fn from_i8(n: i8) -> Option<Self>;
fn from_i16(n: i16) -> Option<Self>;
fn from_i32(n: i32) -> Option<Self>;
fn from_i64(n: i64) -> Option<Self>;
fn from_u8(n: u8) -> Option<Self>;
fn from_u16(n: u16) -> Option<Self>;
fn from_u32(n: u32) -> Option<Self>;
fn from_u64(n: u64) -> Option<Self>;
}
macro_rules! impl_from_primitive_for_int {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
}
};
}
macro_rules! impl_from_primitive_for_uint {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
}
};
}
macro_rules! impl_from_primitive_for_float {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as Self)
}
}
};
}
impl_from_primitive_for_int!(isize);
impl_from_primitive_for_int!(i8);
impl_from_primitive_for_int!(i16);
impl_from_primitive_for_int!(i32);
impl_from_primitive_for_int!(i64);
impl_from_primitive_for_uint!(usize);
impl_from_primitive_for_uint!(u8);
impl_from_primitive_for_uint!(u16);
impl_from_primitive_for_uint!(u32);
impl_from_primitive_for_uint!(u64);
impl_from_primitive_for_float!(f32);
impl_from_primitive_for_float!(f64);
serde_if_integer128! {
impl FromPrimitive for i128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as i128)
}
}
impl FromPrimitive for u128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as u128)
}
}
}
+216 -138
View File
@@ -7,11 +7,10 @@ use de::{
#[cfg(any(core_duration, feature = "std", feature = "alloc"))]
use de::MapAccess;
use __private::de::InPlaceSeed;
use de::from_primitive::FromPrimitive;
use seed::InPlaceSeed;
#[cfg(any(feature = "std", feature = "alloc"))]
use __private::de::size_hint;
use __private::size_hint;
////////////////////////////////////////////////////////////////////////////////
@@ -81,38 +80,8 @@ impl<'de> Deserialize<'de> for bool {
////////////////////////////////////////////////////////////////////////////////
macro_rules! visit_integer_method {
($src_ty:ident, $method:ident, $from_method:ident, $group:ident, $group_ty:ident) => {
#[inline]
fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E>
where
E: Error,
{
match FromPrimitive::$from_method(v) {
Some(v) => Ok(v),
None => Err(Error::invalid_value(
Unexpected::$group(v as $group_ty),
&self,
)),
}
}
};
}
macro_rules! visit_float_method {
($src_ty:ident, $method:ident) => {
#[inline]
fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v as Self::Value)
}
};
}
macro_rules! impl_deserialize_num {
($ty:ident, $method:ident, $($visit:ident),*) => {
($ty:ident, $deserialize:ident $($methods:tt)*) => {
impl<'de> Deserialize<'de> for $ty {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -128,131 +97,221 @@ macro_rules! impl_deserialize_num {
formatter.write_str(stringify!($ty))
}
$(
impl_deserialize_num!($visit $ty);
)*
$($methods)*
}
deserializer.$method(PrimitiveVisitor)
deserializer.$deserialize(PrimitiveVisitor)
}
}
};
(integer $ty:ident) => {
visit_integer_method!(i8, visit_i8, from_i8, Signed, i64);
visit_integer_method!(i16, visit_i16, from_i16, Signed, i64);
visit_integer_method!(i32, visit_i32, from_i32, Signed, i64);
visit_integer_method!(i64, visit_i64, from_i64, Signed, i64);
visit_integer_method!(u8, visit_u8, from_u8, Unsigned, u64);
visit_integer_method!(u16, visit_u16, from_u16, Unsigned, u64);
visit_integer_method!(u32, visit_u32, from_u32, Unsigned, u64);
visit_integer_method!(u64, visit_u64, from_u64, Unsigned, u64);
};
(float $ty:ident) => {
visit_float_method!(f32, visit_f32);
visit_float_method!(f64, visit_f64);
};
}
impl_deserialize_num!(i8, deserialize_i8, integer);
impl_deserialize_num!(i16, deserialize_i16, integer);
impl_deserialize_num!(i32, deserialize_i32, integer);
impl_deserialize_num!(i64, deserialize_i64, integer);
impl_deserialize_num!(isize, deserialize_i64, integer);
impl_deserialize_num!(u8, deserialize_u8, integer);
impl_deserialize_num!(u16, deserialize_u16, integer);
impl_deserialize_num!(u32, deserialize_u32, integer);
impl_deserialize_num!(u64, deserialize_u64, integer);
impl_deserialize_num!(usize, deserialize_u64, integer);
impl_deserialize_num!(f32, deserialize_f32, integer, float);
impl_deserialize_num!(f64, deserialize_f64, integer, float);
serde_if_integer128! {
impl<'de> Deserialize<'de> for i128 {
macro_rules! num_self {
($ty:ident : $visit:ident) => {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
D: Deserializer<'de>,
E: Error,
{
struct PrimitiveVisitor;
Ok(v)
}
};
}
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = i128;
macro_rules! num_as_self {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v as Self::Value)
}
)*
};
}
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("i128")
}
impl_deserialize_num!(integer i128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
if v <= i128::max_value() as u128 {
Ok(v as i128)
} else {
Err(Error::invalid_value(Unexpected::Other("u128"), &self))
}
macro_rules! int_to_int {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if Self::Value::min_value() as i64 <= v as i64 && v as i64 <= Self::Value::max_value() as i64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
}
)*
};
}
deserializer.deserialize_i128(PrimitiveVisitor)
macro_rules! int_to_uint {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if 0 <= v && v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
}
)*
};
}
macro_rules! uint_to_self {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self))
}
}
)*
};
}
impl_deserialize_num! {
i8, deserialize_i8
num_self!(i8:visit_i8);
int_to_int!(i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i16, deserialize_i16
num_self!(i16:visit_i16);
num_as_self!(i8:visit_i8);
int_to_int!(i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i32, deserialize_i32
num_self!(i32:visit_i32);
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i64, deserialize_i64
num_self!(i64:visit_i64);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
isize, deserialize_i64
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u8, deserialize_u8
num_self!(u8:visit_u8);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u16, deserialize_u16
num_self!(u16:visit_u16);
num_as_self!(u8:visit_u8);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u32, deserialize_u32
num_self!(u32:visit_u32);
num_as_self!(u8:visit_u8 u16:visit_u16);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u64:visit_u64);
}
impl_deserialize_num! {
u64, deserialize_u64
num_self!(u64:visit_u64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
}
impl_deserialize_num! {
usize, deserialize_u64
num_as_self!(u8:visit_u8 u16:visit_u16);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
f32, deserialize_f32
num_self!(f32:visit_f32);
num_as_self!(f64:visit_f64);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
f64, deserialize_f64
num_self!(f64:visit_f64);
num_as_self!(f32:visit_f32);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
serde_if_integer128! {
impl_deserialize_num! {
i128, deserialize_i128
num_self!(i128:visit_i128);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
if v <= i128::max_value() as u128 {
Ok(v as i128)
} else {
Err(Error::invalid_value(Unexpected::Other("u128"), &self))
}
}
}
impl<'de> Deserialize<'de> for u128 {
impl_deserialize_num! {
u128, deserialize_u128
num_self!(u128:visit_u128);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
D: Deserializer<'de>,
E: Error,
{
struct PrimitiveVisitor;
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = u128;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("u128")
}
impl_deserialize_num!(integer u128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
if v >= 0 {
Ok(v as u128)
} else {
Err(Error::invalid_value(Unexpected::Other("i128"), &self))
}
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
if 0 <= v {
Ok(v as u128)
} else {
Err(Error::invalid_value(Unexpected::Other("i128"), &self))
}
deserializer.deserialize_u128(PrimitiveVisitor)
}
}
}
@@ -1987,6 +2046,17 @@ impl<'de> Deserialize<'de> for SystemTime {
}
}
fn check_overflow<E>(secs: u64, nanos: u32) -> Result<(), E>
where
E: Error,
{
static NANOS_PER_SEC: u32 = 1_000_000_000;
match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(_) => Ok(()),
None => Err(E::custom("overflow deserializing SystemTime epoch offset")),
}
}
struct DurationVisitor;
impl<'de> Visitor<'de> for DurationVisitor {
@@ -2012,6 +2082,7 @@ impl<'de> Deserialize<'de> for SystemTime {
return Err(Error::invalid_length(1, &self));
}
};
try!(check_overflow(secs, nanos));
Ok(Duration::new(secs, nanos))
}
@@ -2049,13 +2120,20 @@ impl<'de> Deserialize<'de> for SystemTime {
Some(nanos) => nanos,
None => return Err(<A::Error as Error>::missing_field("nanos_since_epoch")),
};
try!(check_overflow(secs, nanos));
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
Ok(UNIX_EPOCH + duration)
#[cfg(systemtime_checked_add)]
let ret = UNIX_EPOCH
.checked_add(duration)
.ok_or_else(|| D::Error::custom("overflow deserializing SystemTime"));
#[cfg(not(systemtime_checked_add))]
let ret = Ok(UNIX_EPOCH + duration);
ret
}
}
+1 -2
View File
@@ -118,7 +118,6 @@ use lib::*;
pub mod value;
mod from_primitive;
mod ignored_any;
mod impls;
mod utf8;
@@ -1008,7 +1007,7 @@ pub trait Deserializer<'de>: Sized {
/// `Deserializer`.
///
/// If the `Visitor` would benefit from taking ownership of `String` data,
/// indiciate this to the `Deserializer` by using `deserialize_string`
/// indicate this to the `Deserializer` by using `deserialize_string`
/// instead.
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
+19
View File
@@ -0,0 +1,19 @@
use de::{Deserialize, DeserializeSeed, Deserializer};
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
///
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
where
T: Deserialize<'de>,
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_in_place(deserializer, self.0)
}
}
+1 -1
View File
@@ -24,7 +24,7 @@
use lib::*;
use self::private::{First, Second};
use __private::de::size_hint;
use __private::size_hint;
use de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
use ser;
+7 -4
View File
@@ -44,7 +44,7 @@
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//! definition.
//! - [JSON5], A superset of JSON including some productions from ES5.
//! - [JSON5], a superset of JSON including some productions from ES5.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [URL] query strings, in the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
@@ -84,7 +84,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.122")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.129")]
// 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
@@ -120,6 +120,7 @@
zero_prefixed_literal,
// correctly used
enum_glob_use,
let_underscore_drop,
map_err_ignore,
result_unit_err,
wildcard_imports,
@@ -138,7 +139,6 @@
)
)]
// Rustc lints.
#![forbid(unsafe_code)]
#![deny(missing_docs, unused_imports)]
////////////////////////////////////////////////////////////////////////////////
@@ -157,7 +157,7 @@ mod lib {
pub use std::*;
}
pub use self::core::{cmp, iter, mem, num, slice, str};
pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
pub use self::core::{f32, f64};
pub use self::core::{i16, i32, i64, i8, isize};
pub use self::core::{u16, u32, u64, u8, usize};
@@ -276,6 +276,9 @@ use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;
#[path = "de/seed.rs"]
mod seed;
#[cfg(not(feature = "std"))]
mod std_error;
+51 -73
View File
@@ -1,10 +1,10 @@
use lib::*;
use de::value::{BorrowedBytesDeserializer, BytesDeserializer};
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
use de::{Deserialize, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))]
use de::{MapAccess, Unexpected};
use de::{DeserializeSeed, MapAccess, Unexpected};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{
@@ -13,6 +13,8 @@ pub use self::content::{
TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor,
};
pub use seed::InPlaceSeed;
/// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error.
pub fn missing_field<'de, V, E>(field: &'static str) -> Result<V, E>
@@ -189,29 +191,6 @@ where
.map(From::from)
}
pub mod size_hint {
use lib::*;
pub fn from_bounds<I>(iter: &I) -> Option<usize>
where
I: Iterator,
{
helper(iter.size_hint())
}
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
}
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
match bounds {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
mod content {
// This module is private and nothing here should be used outside of
@@ -226,7 +205,7 @@ mod content {
use lib::*;
use super::size_hint;
use __private::size_hint;
use de::{
self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny,
MapAccess, SeqAccess, Unexpected, Visitor,
@@ -1043,6 +1022,25 @@ mod content {
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
match self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
}
fn visit_content_seq<'de, V, E>(content: Vec<Content<'de>>, visitor: V) -> Result<V::Value, E>
@@ -1182,25 +1180,14 @@ mod content {
where
V: Visitor<'de>,
{
match self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -1300,8 +1287,9 @@ mod content {
// }
//
// We want {"topic":"Info"} to deserialize even though
// ordinarily unit structs do not deserialize from empty map.
// ordinarily unit structs do not deserialize from empty map/seq.
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
Content::Seq(ref v) if v.is_empty() => visitor.visit_unit(),
_ => self.deserialize_any(visitor),
}
}
@@ -1754,6 +1742,25 @@ mod content {
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
match *self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
}
fn visit_content_seq_ref<'a, 'de, V, E>(
@@ -1901,25 +1908,14 @@ mod content {
where
V: Visitor<'de>,
{
match *self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -2658,24 +2654,6 @@ where
}
}
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
///
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
where
T: Deserialize<'de>,
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_in_place(deserializer, self.0)
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
@@ -2854,7 +2832,7 @@ where
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
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 {
self.pending_content = Some(content);
@@ -2956,7 +2934,7 @@ where
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
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
+5
View File
@@ -1,6 +1,10 @@
#[cfg(serde_derive)]
pub mod de;
#[cfg(serde_derive)]
pub mod ser;
pub mod size_hint;
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
pub mod doc;
@@ -10,6 +14,7 @@ pub use lib::default::Default;
pub use lib::fmt::{self, Formatter};
pub use lib::marker::PhantomData;
pub use lib::option::Option::{self, None, Some};
pub use lib::ptr;
pub use lib::result::Result::{self, Err, Ok};
pub use self::string::from_utf8_lossy;
+21
View File
@@ -0,0 +1,21 @@
use lib::*;
pub fn from_bounds<I>(iter: &I) -> Option<usize>
where
I: Iterator,
{
helper(iter.size_hint())
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
}
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
match bounds {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
+54 -1
View File
@@ -674,6 +674,52 @@ impl Serialize for net::IpAddr {
}
}
#[cfg(feature = "std")]
const DEC_DIGITS_LUT: &'static [u8] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";
#[cfg(feature = "std")]
#[inline]
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
if n >= 100 {
let d1 = ((n % 100) << 1) as usize;
n /= 100;
out[0] = b'0' + n;
out[1] = DEC_DIGITS_LUT[d1];
out[2] = DEC_DIGITS_LUT[d1 + 1];
3
} else if n >= 10 {
let d1 = (n << 1) as usize;
out[0] = DEC_DIGITS_LUT[d1];
out[1] = DEC_DIGITS_LUT[d1 + 1];
2
} else {
out[0] = b'0' + n;
1
}
}
#[cfg(feature = "std")]
#[test]
fn test_format_u8() {
let mut i = 0u8;
loop {
let mut buf = [0u8; 3];
let written = format_u8(i, &mut buf);
assert_eq!(i.to_string().as_bytes(), &buf[..written]);
match i.checked_add(1) {
Some(next) => i = next,
None => break,
}
}
}
#[cfg(feature = "std")]
impl Serialize for net::Ipv4Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -683,7 +729,14 @@ impl Serialize for net::Ipv4Addr {
if serializer.is_human_readable() {
const MAX_LEN: usize = 15;
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
serialize_display_bounded_length!(self, MAX_LEN, serializer)
let mut buf = [b'.'; MAX_LEN];
let mut written = format_u8(self.octets()[0], &mut buf);
for oct in &self.octets()[1..] {
// Skip over delimiters that we initialized buf with
written += format_u8(*oct, &mut buf[written + 1..]) + 1;
}
// We've only written ASCII bytes to the buffer, so it is valid UTF-8
serializer.serialize_str(unsafe { str::from_utf8_unchecked(&buf[..written]) })
} else {
self.octets().serialize(serializer)
}
+26 -4
View File
@@ -1279,9 +1279,20 @@ pub trait Serializer: Sized {
{
let iter = iter.into_iter();
let mut serializer = try!(self.serialize_seq(iterator_len_hint(&iter)));
for item in iter {
try!(serializer.serialize_element(&item));
#[cfg(iterator_try_fold)]
{
let mut iter = iter;
try!(iter.try_for_each(|item| serializer.serialize_element(&item)));
}
#[cfg(not(iterator_try_fold))]
{
for item in iter {
try!(serializer.serialize_element(&item));
}
}
serializer.end()
}
@@ -1319,9 +1330,20 @@ pub trait Serializer: Sized {
{
let iter = iter.into_iter();
let mut serializer = try!(self.serialize_map(iterator_len_hint(&iter)));
for (key, value) in iter {
try!(serializer.serialize_entry(&key, &value));
#[cfg(iterator_try_fold)]
{
let mut iter = iter;
try!(iter.try_for_each(|(key, value)| serializer.serialize_entry(&key, &value)));
}
#[cfg(not(iterator_try_fold))]
{
for (key, value) in iter {
try!(serializer.serialize_entry(&key, &value));
}
}
serializer.end()
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.122" # remember to update html_root_url
version = "1.0.129" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
+6
View File
@@ -16,6 +16,12 @@ fn main() {
if minor >= 37 {
println!("cargo:rustc-cfg=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=ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
+2 -2
View File
@@ -49,7 +49,7 @@ pub fn with_where_predicates_from_fields(
let predicates = cont
.data
.all_fields()
.flat_map(|field| from_field(&field.attrs))
.filter_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone();
@@ -71,7 +71,7 @@ pub fn with_where_predicates_from_variants(
let predicates = variants
.iter()
.flat_map(|variant| from_variant(&variant.attrs))
.filter_map(|variant| from_variant(&variant.attrs))
.flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone();
+51 -25
View File
@@ -8,13 +8,17 @@ use bound;
use dummy;
use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, ungroup, Ctxt, Derive};
use internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
use pretend;
use std::collections::BTreeSet;
use std::ptr;
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_deserialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input);
let ctxt = Ctxt::new();
let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) {
Some(cont) => cont,
@@ -32,7 +36,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let used = pretend::pretend_used(&cont);
let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
impl #de_impl_generics #ident #ty_generics #where_clause {
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
@@ -121,6 +125,9 @@ struct Parameters {
/// At least one field has a serde(getter) attribute, implying that the
/// remote type has a private field.
has_getter: bool,
/// Type has a repr(packed) attribute.
is_packed: bool,
}
impl Parameters {
@@ -133,6 +140,7 @@ impl Parameters {
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.data.has_getter();
let is_packed = cont.attrs.is_packed();
Parameters {
local,
@@ -140,6 +148,7 @@ impl Parameters {
generics,
borrowed,
has_getter,
is_packed,
}
}
@@ -471,7 +480,7 @@ fn deserialize_tuple(
};
let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, false, cattrs, &expecting,
&type_path, params, fields, false, cattrs, expecting,
));
let visitor_expr = quote! {
@@ -557,7 +566,7 @@ fn deserialize_tuple_in_place(
None
};
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
let visitor_expr = quote! {
__Visitor {
@@ -918,7 +927,7 @@ fn deserialize_struct(
let expecting = cattrs.expecting().unwrap_or(&expecting);
let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, true, cattrs, &expecting,
&type_path, params, fields, true, cattrs, expecting,
));
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
@@ -1059,7 +1068,7 @@ fn deserialize_struct_in_place(
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
let (field_visitor, fields_stmt, visit_map) =
deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs);
@@ -1724,6 +1733,8 @@ fn deserialize_externally_tagged_variant(
}
}
// Generates significant part of the visit_seq and visit_map bodies of visitors
// for the variants of internally tagged enum.
fn deserialize_internally_tagged_variant(
params: &Parameters,
variant: &Variant,
@@ -1775,11 +1786,9 @@ fn deserialize_untagged_variant(
deserializer: TokenStream,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
return quote_block! {
#wrapper
_serde::__private::Result::map(
<#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
_serde::__private::Result::map(#path(#deserializer), #unwrap_fn)
};
}
@@ -2083,7 +2092,7 @@ fn deserialize_identifier(
) -> Fragment {
let mut flat_fields = Vec::new();
for (_, ident, aliases) in fields {
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)));
}
let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect();
@@ -2281,7 +2290,7 @@ fn deserialize_identifier(
};
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields {
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(&fallthrough_arm);
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm);
Some(quote! {
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
where
@@ -2879,44 +2888,61 @@ fn wrap_deserialize_variant_with(
variant: &Variant,
deserialize_with: &syn::ExprPath,
) -> (TokenStream, TokenStream, TokenStream) {
let this = &params.this;
let variant_ident = &variant.ident;
let field_tys = variant.fields.iter().map(|field| field.ty);
let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with);
let unwrap_fn = unwrap_to_variant_closure(params, variant, true);
(wrapper, wrapper_ty, unwrap_fn)
}
// Generates closure that converts single input parameter to the final value.
fn unwrap_to_variant_closure(
params: &Parameters,
variant: &Variant,
with_wrapper: bool,
) -> TokenStream {
let this = &params.this;
let variant_ident = &variant.ident;
let (arg, wrapper) = if with_wrapper {
(quote! { __wrap }, quote! { __wrap.value })
} else {
let field_tys = variant.fields.iter().map(|field| field.ty);
(quote! { __wrap: (#(#field_tys),*) }, quote! { __wrap })
};
let field_access = (0..variant.fields.len()).map(|n| {
Member::Unnamed(Index {
index: n as u32,
span: Span::call_site(),
})
});
let unwrap_fn = match variant.style {
match variant.style {
Style::Struct if variant.fields.len() == 1 => {
let member = &variant.fields[0].member;
quote! {
|__wrap| #this::#variant_ident { #member: __wrap.value }
|#arg| #this::#variant_ident { #member: #wrapper }
}
}
Style::Struct => {
let members = variant.fields.iter().map(|field| &field.member);
quote! {
|__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* }
|#arg| #this::#variant_ident { #(#members: #wrapper.#field_access),* }
}
}
Style::Tuple => quote! {
|__wrap| #this::#variant_ident(#(__wrap.value.#field_access),*)
|#arg| #this::#variant_ident(#(#wrapper.#field_access),*)
},
Style::Newtype => quote! {
|__wrap| #this::#variant_ident(__wrap.value)
|#arg| #this::#variant_ident(#wrapper)
},
Style::Unit => quote! {
|__wrap| #this::#variant_ident
|#arg| #this::#variant_ident
},
};
(wrapper, wrapper_ty, unwrap_fn)
}
}
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
+1 -1
View File
@@ -23,7 +23,7 @@ pub fn wrap_in_const(
use #path as _serde;
},
None => quote! {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
},
};
+1 -1
View File
@@ -23,7 +23,7 @@ pub struct Container<'a> {
/// The fields of a struct or enum.
///
/// Analagous to `syn::Data`.
/// Analogous to `syn::Data`.
pub enum Data<'a> {
Enum(Vec<Variant<'a>>),
Struct(Style, Vec<Field<'a>>),
+37 -24
View File
@@ -1,6 +1,7 @@
use internals::respan::respan;
use internals::symbol::*;
use internals::{ungroup, Ctxt};
use proc_macro2::{Group, Span, TokenStream, TokenTree};
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::borrow::Cow;
use std::collections::BTreeSet;
@@ -555,7 +556,7 @@ impl Container {
// Parse `#[serde(crate = "foo")]`
Meta(NameValue(m)) if m.path == CRATE => {
if let Ok(path) = parse_lit_into_path(cx, CRATE, &m.lit) {
serde_path.set(&m.path, path)
serde_path.set(&m.path, path);
}
}
@@ -1608,7 +1609,7 @@ fn get_lit_str2<'a>(
fn parse_lit_into_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = get_lit_str(cx, attr_name, lit)?;
parse_lit_str(string).map_err(|_| {
cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()));
})
}
@@ -1619,7 +1620,7 @@ fn parse_lit_into_expr_path(
) -> Result<syn::ExprPath, ()> {
let string = get_lit_str(cx, attr_name, lit)?;
parse_lit_str(string).map_err(|_| {
cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()));
})
}
@@ -1648,7 +1649,7 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn
cx.error_spanned_by(
lit,
format!("failed to parse type: {} = {:?}", attr_name, string.value()),
)
);
})
}
@@ -1901,14 +1902,41 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
syn::Type::Group(ty) => {
collect_lifetimes(&ty.elem, out);
}
syn::Type::Macro(ty) => {
collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out);
}
syn::Type::BareFn(_)
| syn::Type::Never(_)
| syn::Type::TraitObject(_)
| syn::Type::ImplTrait(_)
| syn::Type::Infer(_)
| syn::Type::Macro(_)
| syn::Type::Verbatim(_)
| _ => {}
| syn::Type::Verbatim(_) => {}
#[cfg(test)]
syn::Type::__TestExhaustive(_) => unimplemented!(),
#[cfg(not(test))]
_ => {}
}
}
fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet<syn::Lifetime>) {
let mut iter = tokens.into_iter();
while let Some(tt) = iter.next() {
match &tt {
TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
if let Some(TokenTree::Ident(ident)) = iter.next() {
out.insert(syn::Lifetime {
apostrophe: op.span(),
ident,
});
}
}
TokenTree::Group(group) => {
let tokens = group.stream();
collect_lifetimes_from_tokens(tokens, out);
}
_ => {}
}
}
}
@@ -1922,20 +1950,5 @@ where
fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> {
let stream = syn::parse_str(&s.value())?;
Ok(respan_token_stream(stream, s.span()))
}
fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
stream
.into_iter()
.map(|token| respan_token_tree(token, span))
.collect()
}
fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
if let TokenTree::Group(g) = &mut token {
*g = Group::new(g.delimiter(), respan_token_stream(g.stream(), span));
}
token.set_span(span);
token
Ok(respan(stream, s.span()))
}
+2 -2
View File
@@ -260,7 +260,7 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by(
cont.original,
format!("variant field name `{}` conflicts with internal tag", tag),
)
);
};
for variant in variants {
@@ -396,7 +396,7 @@ fn member_message(member: &Member) -> String {
}
fn allow_transparent(field: &Field, derive: Derive) -> bool {
if let Type::Path(ty) = ungroup(&field.ty) {
if let Type::Path(ty) = ungroup(field.ty) {
if let Some(seg) = ty.path.segments.last() {
if seg.ident == "PhantomData" {
return false;
+4
View File
@@ -4,8 +4,12 @@ pub mod attr;
mod ctxt;
pub use self::ctxt::Ctxt;
mod receiver;
pub use self::receiver::replace_receiver;
mod case;
mod check;
mod respan;
mod symbol;
use syn::Type;
+287
View File
@@ -0,0 +1,287 @@
use internals::respan::respan;
use proc_macro2::Span;
use quote::ToTokens;
use std::mem;
use syn::punctuated::Punctuated;
use syn::{
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate,
};
pub fn replace_receiver(input: &mut DeriveInput) {
let self_ty = {
let ident = &input.ident;
let ty_generics = input.generics.split_for_impl().1;
parse_quote!(#ident #ty_generics)
};
let mut visitor = ReplaceReceiver(&self_ty);
visitor.visit_generics_mut(&mut input.generics);
visitor.visit_data_mut(&mut input.data);
}
struct ReplaceReceiver<'a>(&'a TypePath);
impl ReplaceReceiver<'_> {
fn self_ty(&self, span: Span) -> TypePath {
let tokens = self.0.to_token_stream();
let respanned = respan(tokens, span);
syn::parse2(respanned).unwrap()
}
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
if path.leading_colon.is_some() || path.segments[0].ident != "Self" {
return;
}
if path.segments.len() == 1 {
self.self_to_expr_path(path);
return;
}
let span = path.segments[0].ident.span();
*qself = Some(QSelf {
lt_token: Token![<](span),
ty: Box::new(Type::Path(self.self_ty(span))),
position: 0,
as_token: None,
gt_token: Token![>](span),
});
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
let segments = mem::replace(&mut path.segments, Punctuated::new());
path.segments = segments.into_pairs().skip(1).collect();
}
fn self_to_expr_path(&self, path: &mut Path) {
let self_ty = self.self_ty(path.segments[0].ident.span());
let variant = mem::replace(path, self_ty.path);
for segment in &mut path.segments {
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
bracketed.colon2_token = Some(<Token![::]>::default());
}
}
}
if variant.segments.len() > 1 {
path.segments.push_punct(<Token![::]>::default());
path.segments.extend(variant.segments.into_pairs().skip(1));
}
}
}
impl ReplaceReceiver<'_> {
// `Self` -> `Receiver`
fn visit_type_mut(&mut self, ty: &mut Type) {
let span = if let Type::Path(node) = ty {
if node.qself.is_none() && node.path.is_ident("Self") {
node.path.segments[0].ident.span()
} else {
self.visit_type_path_mut(node);
return;
}
} else {
self.visit_type_mut_impl(ty);
return;
};
*ty = self.self_ty(span).into();
}
// `Self::Assoc` -> `<Receiver>::Assoc`
fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
if ty.qself.is_none() {
self.self_to_qself(&mut ty.qself, &mut ty.path);
}
self.visit_type_path_mut_impl(ty);
}
// `Self::method` -> `<Receiver>::method`
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
if expr.qself.is_none() {
self.self_to_qself(&mut expr.qself, &mut expr.path);
}
self.visit_expr_path_mut_impl(expr);
}
// Everything below is simply traversing the syntax tree.
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
match ty {
Type::Array(ty) => {
self.visit_type_mut(&mut ty.elem);
self.visit_expr_mut(&mut ty.len);
}
Type::BareFn(ty) => {
for arg in &mut ty.inputs {
self.visit_type_mut(&mut arg.ty);
}
self.visit_return_type_mut(&mut ty.output);
}
Type::Group(ty) => self.visit_type_mut(&mut ty.elem),
Type::ImplTrait(ty) => {
for bound in &mut ty.bounds {
self.visit_type_param_bound_mut(bound);
}
}
Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac),
Type::Paren(ty) => self.visit_type_mut(&mut ty.elem),
Type::Path(ty) => {
if let Some(qself) = &mut ty.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut ty.path);
}
Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem),
Type::Reference(ty) => self.visit_type_mut(&mut ty.elem),
Type::Slice(ty) => self.visit_type_mut(&mut ty.elem),
Type::TraitObject(ty) => {
for bound in &mut ty.bounds {
self.visit_type_param_bound_mut(bound);
}
}
Type::Tuple(ty) => {
for elem in &mut ty.elems {
self.visit_type_mut(elem);
}
}
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
#[cfg(test)]
Type::__TestExhaustive(_) => unimplemented!(),
#[cfg(not(test))]
_ => {}
}
}
fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) {
if let Some(qself) = &mut ty.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut ty.path);
}
fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) {
if let Some(qself) = &mut expr.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut expr.path);
}
fn visit_path_mut(&mut self, path: &mut Path) {
for segment in &mut path.segments {
self.visit_path_arguments_mut(&mut segment.arguments);
}
}
fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) {
match arguments {
PathArguments::None => {}
PathArguments::AngleBracketed(arguments) => {
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::Lifetime(_)
| GenericArgument::Constraint(_)
| GenericArgument::Const(_) => {}
}
}
}
PathArguments::Parenthesized(arguments) => {
for argument in &mut arguments.inputs {
self.visit_type_mut(argument);
}
self.visit_return_type_mut(&mut arguments.output);
}
}
}
fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) {
match return_type {
ReturnType::Default => {}
ReturnType::Type(_, output) => self.visit_type_mut(output),
}
}
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(_) => {}
}
}
fn visit_generics_mut(&mut self, generics: &mut Generics) {
for param in &mut generics.params {
match param {
GenericParam::Type(param) => {
for bound in &mut param.bounds {
self.visit_type_param_bound_mut(bound);
}
}
GenericParam::Lifetime(_) | GenericParam::Const(_) => {}
}
}
if let Some(where_clause) = &mut generics.where_clause {
for predicate in &mut where_clause.predicates {
match predicate {
WherePredicate::Type(predicate) => {
self.visit_type_mut(&mut predicate.bounded_ty);
for bound in &mut predicate.bounds {
self.visit_type_param_bound_mut(bound);
}
}
WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {}
}
}
}
}
fn visit_data_mut(&mut self, data: &mut Data) {
match data {
Data::Struct(data) => {
for field in &mut data.fields {
self.visit_type_mut(&mut field.ty);
}
}
Data::Enum(data) => {
for variant in &mut data.variants {
for field in &mut variant.fields {
self.visit_type_mut(&mut field.ty);
}
}
}
Data::Union(_) => {}
}
}
fn visit_expr_mut(&mut self, expr: &mut Expr) {
match expr {
Expr::Binary(expr) => {
self.visit_expr_mut(&mut expr.left);
self.visit_expr_mut(&mut expr.right);
}
Expr::Call(expr) => {
self.visit_expr_mut(&mut expr.func);
for arg in &mut expr.args {
self.visit_expr_mut(arg);
}
}
Expr::Cast(expr) => {
self.visit_expr_mut(&mut expr.expr);
self.visit_type_mut(&mut expr.ty);
}
Expr::Field(expr) => self.visit_expr_mut(&mut expr.base),
Expr::Index(expr) => {
self.visit_expr_mut(&mut expr.expr);
self.visit_expr_mut(&mut expr.index);
}
Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr),
Expr::Path(expr) => self.visit_expr_path_mut(expr),
Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr),
_ => {}
}
}
fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
}
+16
View File
@@ -0,0 +1,16 @@
use proc_macro2::{Group, Span, TokenStream, TokenTree};
pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream {
stream
.into_iter()
.map(|token| respan_token(token, span))
.collect()
}
fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
if let TokenTree::Group(g) = &mut token {
*g = Group::new(g.delimiter(), respan(g.stream(), span));
}
token.set_span(span);
token
}
+14 -6
View File
@@ -13,13 +13,19 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.122")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.129")]
#![allow(unknown_lints, bare_trait_objects)]
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
clippy::branches_sharing_code,
clippy::cognitive_complexity,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
clippy::collapsible_match,
clippy::enum_variant_names,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
clippy::manual_map,
clippy::match_like_matches_macro,
clippy::needless_pass_by_value,
clippy::too_many_arguments,
@@ -35,11 +41,13 @@
clippy::checked_conversions,
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::filter_map,
clippy::indexing_slicing,
clippy::items_after_statements,
clippy::let_underscore_drop,
clippy::map_err_ignore,
clippy::match_same_arms,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
clippy::match_wildcard_for_single_variants,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::option_if_let_else,
@@ -79,16 +87,16 @@ mod try;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&input)
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(to_compile_errors)
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&input)
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(to_compile_errors)
.into()
}
+101 -42
View File
@@ -1,7 +1,7 @@
use proc_macro2::{Span, TokenStream};
use syn::Ident;
use proc_macro2::TokenStream;
use quote::format_ident;
use internals::ast::{Container, Data, Field, Style};
use internals::ast::{Container, Data, Field, Style, Variant};
// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
@@ -20,8 +20,8 @@ use internals::ast::{Container, Data, Field, Style};
// 8 | enum EnumDef { V }
// | ^
//
pub fn pretend_used(cont: &Container) -> TokenStream {
let pretend_fields = pretend_fields_used(cont);
pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
let pretend_fields = pretend_fields_used(cont, is_packed);
let pretend_variants = pretend_variants_used(cont);
quote! {
@@ -32,49 +32,115 @@ pub fn pretend_used(cont: &Container) -> TokenStream {
// For structs with named fields, expands to:
//
// match None::<&T> {
// Some(T { a: __v0, b: __v1 }) => {}
// _ => {}
// }
//
// For packed structs on sufficiently new rustc, expands to:
//
// match None::<&T> {
// Some(__v @ T { a: _, b: _ }) => {
// let _ = addr_of!(__v.a);
// let _ = addr_of!(__v.b);
// }
// _ => {}
// }
//
// For packed structs on older rustc, we assume Sized and !Drop, and expand to:
//
// match None::<T> {
// Some(T { a: ref __v0, b: ref __v1 }) => {}
// Some(T { a: __v0, b: __v1 }) => {}
// _ => {}
// }
//
// For enums, expands to the following but only including struct variants:
//
// match None::<T> {
// Some(T::A { a: ref __v0 }) => {}
// Some(T::B { b: ref __v0 }) => {}
// match None::<&T> {
// Some(T::A { a: __v0 }) => {}
// Some(T::B { b: __v0 }) => {}
// _ => {}
// }
//
// The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop
// impl.
fn pretend_fields_used(cont: &Container) -> TokenStream {
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
match &cont.data {
Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
Data::Struct(Style::Struct, fields) => if is_packed {
pretend_fields_used_struct_packed(cont, fields)
} else {
pretend_fields_used_struct(cont, fields)
},
Data::Struct(_, _) => quote!(),
}
}
fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
let patterns = match &cont.data {
Data::Enum(variants) => variants
.iter()
.filter_map(|variant| match variant.style {
Style::Struct => {
let variant_ident = &variant.ident;
let pat = struct_pattern(&variant.fields);
Some(quote!(#type_ident::#variant_ident #pat))
}
_ => None,
})
.collect::<Vec<_>>(),
Data::Struct(Style::Struct, fields) => {
let pat = struct_pattern(fields);
vec![quote!(#type_ident #pat)]
}
Data::Struct(_, _) => {
return quote!();
}
};
let members = fields.iter().map(|field| &field.member);
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
}
}
}
fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(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(not(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),* }) => {}
_ => {}
}
}
}
}
fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
let patterns = variants
.iter()
.filter_map(|variant| match variant.style {
Style::Struct => {
let variant_ident = &variant.ident;
let members = variant.fields.iter().map(|field| &field.member);
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
}
_ => None,
})
.collect::<Vec<_>>();
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
#(
_serde::__private::Some(#patterns) => {}
)*
@@ -107,7 +173,7 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
let cases = variants.iter().map(|variant| {
let variant_ident = &variant.ident;
let placeholders = &(0..variant.fields.len())
.map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
.map(|i| format_ident!("__v{}", i))
.collect::<Vec<_>>();
let pat = match variant.style {
@@ -131,10 +197,3 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
quote!(#(#cases)*)
}
fn struct_pattern(fields: &[Field]) -> TokenStream {
let members = fields.iter().map(|field| &field.member);
let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#members: ref #placeholders),* })
}
+8 -4
View File
@@ -6,10 +6,14 @@ use bound;
use dummy;
use fragment::{Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, Ctxt, Derive};
use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend;
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_serialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input);
let ctxt = Ctxt::new();
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
Some(cont) => cont,
@@ -26,7 +30,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let used = pretend::pretend_used(&cont);
let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
@@ -1095,7 +1099,7 @@ fn serialize_struct_visitor(
let mut field_expr = if is_enum {
quote!(#member)
} else {
get_member(params, field, &member)
get_member(params, field, member)
};
let key_expr = field.attrs.name().serialize_name();
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.25.0" # remember to update html_root_url
version = "0.26.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
+12
View File
@@ -0,0 +1,12 @@
use std::path::Path;
fn main() {
// Sometimes on Windows the git checkout does not correctly wire up the
// symlink from serde_derive_internals/src to serde_derive/src/internals.
// When this happens we'll just build based on relative paths within the git
// repo.
let mod_behind_symlink = Path::new("src/mod.rs");
if !mod_behind_symlink.exists() {
println!("cargo:rustc-cfg=serde_build_from_git");
}
}
+14 -2
View File
@@ -1,9 +1,14 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")]
#![allow(unknown_lints, bare_trait_objects)]
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints
#![allow(
clippy::cognitive_complexity,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
clippy::collapsible_match,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
clippy::manual_map,
clippy::missing_panics_doc,
clippy::redundant_field_names,
clippy::result_unit_err,
clippy::should_implement_trait,
@@ -17,11 +22,17 @@
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::items_after_statements,
clippy::let_underscore_drop,
clippy::match_same_arms,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
clippy::match_wildcard_for_single_variants,
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::unused_self,
clippy::wildcard_imports
)]
@@ -31,7 +42,8 @@ extern crate syn;
extern crate proc_macro2;
extern crate quote;
#[path = "src/mod.rs"]
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
mod internals;
pub use internals::*;
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.122" # remember to update html_root_url
version = "1.0.129" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
+3 -1
View File
@@ -144,7 +144,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.122")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.129")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints
@@ -153,8 +153,10 @@
#![cfg_attr(
feature = "cargo-clippy",
allow(
cloned_instead_of_copied,
empty_line_after_outer_attr,
missing_docs_in_private_items,
missing_panics_doc,
module_name_repetitions,
must_use_candidate,
redundant_field_names,
+6 -6
View File
@@ -32,18 +32,18 @@ impl<'a> Serializer<'a> {
}
macro_rules! assert_next_token {
($ser:expr, $actual:ident) => {
($ser:expr, $actual:ident) => {{
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
};
($ser:expr, $actual:ident($v:expr)) => {
}};
($ser:expr, $actual:ident($v:expr)) => {{
assert_next_token!(
$ser,
format_args!(concat!(stringify!($actual), "({:?})"), $v),
Token::$actual(v),
v == $v
);
};
($ser:expr, $actual:ident { $($k:ident),* }) => {
}};
($ser:expr, $actual:ident { $($k:ident),* }) => {{
let compare = ($($k,)*);
let field_format = || {
use std::fmt::Write;
@@ -59,7 +59,7 @@ macro_rules! assert_next_token {
Token::$actual { $($k),* },
($($k,)*) == compare
);
};
}};
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
+2 -2
View File
@@ -10,7 +10,7 @@ enum DeEnum<B, C, D> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<B, C, D> _serde::Serialize for DeEnum<B, C, D>
@@ -265,7 +265,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, B, C, D> _serde::Deserialize<'de> for DeEnum<B, C, D>
@@ -11,7 +11,7 @@ struct DefaultTyParam<T: AssociatedType<X = i32> = i32> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<T: AssociatedType<X = i32>> _serde::Serialize for DefaultTyParam<T> {
@@ -49,7 +49,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, T: AssociatedType<X = i32>> _serde::Deserialize<'de> for DefaultTyParam<T> {
@@ -8,7 +8,7 @@ pub enum GenericEnum<T, U> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<T, U> _serde::Serialize for GenericEnum<T, U>
@@ -114,7 +114,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, T, U> _serde::Deserialize<'de> for GenericEnum<T, U>
@@ -5,7 +5,7 @@ pub struct GenericStruct<T> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<T> _serde::Serialize for GenericStruct<T>
@@ -42,7 +42,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, T> _serde::Deserialize<'de> for GenericStruct<T>
@@ -410,7 +410,7 @@ pub struct GenericNewTypeStruct<T>(T);
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<T> _serde::Serialize for GenericNewTypeStruct<T>
@@ -435,7 +435,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, T> _serde::Deserialize<'de> for GenericNewTypeStruct<T>
@@ -3,7 +3,7 @@ pub struct GenericTupleStruct<T, U>(T, U);
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, T, U> _serde::Deserialize<'de> for GenericTupleStruct<T, U>
@@ -8,7 +8,7 @@ enum Lifetimes<'a> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'a> _serde::Serialize for Lifetimes<'a> {
@@ -95,7 +95,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, 'a> _serde::Deserialize<'de> for Lifetimes<'a> {
@@ -7,7 +7,7 @@ struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'a, 'b, A: 'a, B: 'b, C> _serde::Serialize for SerNamedMap<'a, 'b, A, B, C>
@@ -63,7 +63,7 @@ struct DeNamedMap<A, B, C> {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, A, B, C> _serde::Deserialize<'de> for DeNamedMap<A, B, C>
@@ -3,7 +3,7 @@ struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'a, 'b, A: 'a, B: 'b, C> _serde::Serialize for SerNamedTuple<'a, 'b, A, B, C>
@@ -55,7 +55,7 @@ struct DeNamedTuple<A, B, C>(A, B, C);
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de, A, B, C> _serde::Deserialize<'de> for DeNamedTuple<A, B, C>
@@ -3,7 +3,7 @@ struct NamedUnit;
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl _serde::Serialize for NamedUnit {
@@ -21,7 +21,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for NamedUnit {
+1 -1
View File
@@ -13,7 +13,7 @@ where
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'a, B: 'a, C: 'a, D> _serde::Serialize for SerEnum<'a, B, C, D>
+2 -2
View File
@@ -3,7 +3,7 @@ enum Void {}
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl _serde::Serialize for Void {
@@ -21,7 +21,7 @@ const _: () = {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#[allow(rust_2018_idioms, clippy::useless_attribute)]
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for Void {
+2
View File
@@ -1,6 +1,8 @@
#![allow(
clippy::cast_lossless,
clippy::from_over_into,
// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
clippy::nonstandard_macro_braces,
clippy::trivially_copy_pass_by_ref
)]
+37 -2
View File
@@ -15,7 +15,7 @@ use std::sync::atomic::{
AtomicUsize, Ordering,
};
use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicI64, AtomicU64};
@@ -192,8 +192,12 @@ macro_rules! declare_tests {
}
macro_rules! declare_error_tests {
($($name:ident<$target:ty> { $tokens:expr, $expected:expr, })+) => {
($(
$(#[$cfg:meta])*
$name:ident<$target:ty> { $tokens:expr, $expected:expr, }
)+) => {
$(
$(#[$cfg])*
#[test]
fn $name() {
assert_de_tokens_error::<$target>($tokens, $expected);
@@ -1614,4 +1618,35 @@ declare_error_tests! {
],
"overflow deserializing Duration",
}
test_systemtime_overflow_seq<SystemTime> {
&[
Token::Seq { len: Some(2) },
Token::U64(u64::max_value()),
Token::U32(1_000_000_000),
Token::SeqEnd,
],
"overflow deserializing SystemTime epoch offset",
}
test_systemtime_overflow_struct<SystemTime> {
&[
Token::Struct { name: "SystemTime", len: 2 },
Token::Str("secs_since_epoch"),
Token::U64(u64::max_value()),
Token::Str("nanos_since_epoch"),
Token::U32(1_000_000_000),
Token::StructEnd,
],
"overflow deserializing SystemTime epoch offset",
}
#[cfg(systemtime_checked_add)]
test_systemtime_overflow<SystemTime> {
&[
Token::Seq { len: Some(2) },
Token::U64(u64::max_value()),
Token::U32(0),
Token::SeqEnd,
],
"overflow deserializing SystemTime",
}
}
+91 -3
View File
@@ -3,10 +3,12 @@
// types involved.
#![deny(warnings)]
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
#![allow(
unknown_lints,
mixed_script_confusables,
// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
clippy::nonstandard_macro_braces,
clippy::ptr_arg,
clippy::trivially_copy_pass_by_ref
)]
@@ -266,7 +268,6 @@ fn test_gen() {
}
assert::<EmptyEnumVariant>();
#[cfg(feature = "unstable")]
#[derive(Serialize, Deserialize)]
struct NonAsciiIdents {
σ: f64,
@@ -642,7 +643,7 @@ fn test_gen() {
assert::<SkippedVariant<X>>();
#[derive(Deserialize)]
struct ImpliciltyBorrowedOption<'a> {
struct ImplicitlyBorrowedOption<'a> {
option: std::option::Option<&'a str>,
}
@@ -723,6 +724,24 @@ fn test_gen() {
}
deriving!(&'a str);
macro_rules! mac {
($($tt:tt)*) => {
$($tt)*
};
}
#[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")]
f: mac!(Cow<'a, str>),
}
#[derive(Serialize)]
struct Struct {
#[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>,
}
}
//////////////////////////////////////////////////////////////////////////
@@ -796,3 +815,72 @@ where
pub fn is_zero(n: &u8) -> bool {
*n == 0
}
fn vec_first_element<T, S>(vec: &Vec<T>, serializer: S) -> StdResult<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
vec.first().serialize(serializer)
}
//////////////////////////////////////////////////////////////////////////
#[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
#[serde(deserialize_with = "deserialize_generic")]
Unit,
#[serde(deserialize_with = "deserialize_generic")]
Newtype(i32),
#[serde(deserialize_with = "deserialize_generic")]
Struct { f1: String, f2: u8 },
}
fn deserialize_generic<'de, T, D>(deserializer: D) -> StdResult<T, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
T::deserialize(deserializer)
}
//////////////////////////////////////////////////////////////////////////
#[repr(packed)]
pub struct RemotePacked {
pub a: u16,
pub b: u32,
}
#[derive(Serialize)]
#[repr(packed)]
#[serde(remote = "RemotePacked")]
pub struct RemotePackedDef {
a: u16,
b: u32,
}
impl Drop for RemotePackedDef {
fn drop(&mut self) {}
}
#[repr(packed)]
pub struct RemotePackedNonCopy {
pub a: u16,
pub b: String,
}
#[derive(Deserialize)]
#[repr(packed)]
#[serde(remote = "RemotePackedNonCopy")]
pub struct RemotePackedNonCopyDef {
a: u16,
b: String,
}
impl Drop for RemotePackedNonCopyDef {
fn drop(&mut self) {}
}
+45 -1
View File
@@ -994,6 +994,28 @@ fn test_internally_tagged_struct_variant_containing_unit_variant() {
Token::StructEnd,
],
);
assert_de_tokens(
&Message::Log { level: Level::Info },
&[
Token::Map { len: Some(2) },
Token::Str("action"),
Token::Str("Log"),
Token::Str("level"),
Token::BorrowedStr("Info"),
Token::MapEnd,
],
);
assert_de_tokens(
&Message::Log { level: Level::Info },
&[
Token::Seq { len: Some(2) },
Token::Str("Log"),
Token::BorrowedStr("Info"),
Token::SeqEnd,
],
);
}
#[test]
@@ -1877,9 +1899,31 @@ fn test_internally_tagged_newtype_variant_containing_unit_struct() {
Token::MapEnd,
],
);
assert_de_tokens(
&Message::Info(Info),
&[
Token::Struct {
name: "Message",
len: 1,
},
Token::Str("topic"),
Token::Str("Info"),
Token::StructEnd,
],
);
assert_de_tokens(
&Message::Info(Info),
&[
Token::Seq { len: Some(1) },
Token::Str("Info"),
Token::SeqEnd,
],
);
}
#[deny(safe_packed_borrows)]
#[deny(unaligned_references)]
#[test]
fn test_packed_struct_can_derive_serialize() {
#[derive(Copy, Clone, Serialize)]
+86
View File
@@ -0,0 +1,86 @@
use serde::{Deserialize, Serialize};
#[test]
fn test_self() {
pub trait Trait {
type Assoc;
}
#[derive(Deserialize, Serialize)]
pub struct Generics<T: Trait<Assoc = Self>>
where
Self: Trait<Assoc = Self>,
<Self as Trait>::Assoc: Sized,
{
_f: T,
}
impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
pub struct Struct {
_f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>,
_f4: [(); Self::ASSOC],
_f5: [(); Self::assoc()],
}
impl Struct {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Struct {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
struct Tuple(
Box<Self>,
Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC],
[(); Self::assoc()],
);
impl Tuple {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Tuple {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
enum Enum {
Struct {
_f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>,
_f4: [(); Self::ASSOC],
_f5: [(); Self::assoc()],
},
Tuple(
Box<Self>,
Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC],
[(); Self::assoc()],
),
}
impl Enum {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Enum {
type Assoc = Self;
}
}
+1 -1
View File
@@ -7,4 +7,4 @@ error[E0308]: mismatched types
| expected `u16`, found `u8`
| help: you can convert a `u8` to a `u16`: `Deserialize.into()`
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -6,4 +6,4 @@ error[E0308]: mismatched types
|
= note: expected reference `&u8`
found reference `&u16`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+1 -1
View File
@@ -6,4 +6,4 @@ error[E0308]: mismatched types
|
= note: expected reference `&u8`
found reference `&u16`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -4,4 +4,4 @@ error: #[serde(tag = "...")] can only be used on enums and structs with named fi
3 | #[derive(Serialize)]
| ^^^^^^^^^
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)