Compare commits

...

92 Commits

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

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

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

    failures:

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

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

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

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

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

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

    error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
        --> serde_derive_internals/src/attr.rs:1478:8
         |
    1478 |       Ok(match string.parse() {
         |  ________^
    1479 | |         Ok(ty) => Some(ty),
    1480 | |         Err(_) => {
    1481 | |             cx.error_spanned_by(
    ...    |
    1486 | |         }
    1487 | |     })
         | |_____^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
    help: try this
         |
    1478 ~     Ok(if let Ok(ty) = string.parse() { Some(ty) } else {
    1479 +         cx.error_spanned_by(
    1480 +             &string,
    1481 +             format!("failed to parse type: {} = {:?}", attr_name, string.value()),
    1482 +         );
    1483 +         None
    1484 ~     })
         |
2023-03-17 17:32:50 -07:00
David Tolnay 9fc0d13e2c Merge pull request #2406 from dtolnay/nestedmeta
Rewrite attribute parser using parse_nested_meta
2023-03-17 17:32:39 -07:00
David Tolnay bc22641359 Rewrite attribute parser using parse_nested_meta 2023-03-17 17:23:56 -07:00
David Tolnay 05098105a8 Update compiler version for serde_derive in readme 2023-03-17 17:23:33 -07:00
David Tolnay 5b23634dc6 Merge pull request #2405 from dtolnay/syn
Update to syn 2
2023-03-17 17:23:20 -07:00
David Tolnay 32f0d00ff9 Update to syn 2 2023-03-17 17:17:40 -07:00
David Tolnay 9d87851f0c Merge pull request #2404 from dtolnay/attributeexpr
Add ui test of malformed attribute containing expression
2023-03-17 17:14:54 -07:00
David Tolnay c0296ee11b Add ui test of malformed attribute containing expression 2023-03-16 00:15:54 -07:00
David Tolnay 54671259aa Release 1.0.156 2023-03-14 01:02:18 -07:00
David Tolnay 994f7c7924 Format with rustfmt 1.5.2-nightly 2023-03-14 00:50:38 -07:00
David Tolnay 7a8e4977e2 Merge pull request #2401 from dtolnay/docderive
Show derive macros in serde's rustdoc
2023-03-14 00:37:06 -07:00
David Tolnay fb7b6ea7ea Enable serde derive feature when built by docs.rs 2023-03-14 00:33:41 -07:00
David Tolnay 063dd5b93f Show derive macros in serde's rustdoc 2023-03-14 00:28:20 -07:00
David Tolnay a38aa31ade Merge pull request #2400 from Nilstrieb/explicit-reexport
Use explicit re-export of `serde_derive` to give rustc more info
2023-03-14 00:26:01 -07:00
nils f42b2581da Use explicit re-export of serde_derive to give rustc more info
rustc will start looking behind `#[cfg(FALSE)]` items to start giving
better diagnostics. By using an explicit re-export instead of a glob
export, we tell rustc that `Deserialize` and `Serialize` exist here.
2023-03-14 08:11:38 +01:00
David Tolnay 2ba406726f Release 1.0.155 2023-03-11 12:57:53 -08:00
David Tolnay 7e9826e17b Add link to core CStr stabilization announcement 2023-03-11 12:57:16 -08:00
David Tolnay f4dcc5c918 Merge pull request #2374 from safarir/master
Enable CStr and CString in no-std enviroment
2023-03-11 12:55:49 -08:00
David Tolnay 8b1887c440 Remove unneeded attr_name argument when parsing borrow attr 2023-03-11 11:35:03 -08:00
David Tolnay bbfb1d3504 Merge pull request #2399 from dtolnay/borrow
Eagerly parse variant-level borrow attribute instead of deferring entire Meta
2023-03-11 11:29:55 -08:00
David Tolnay e106feb5ec Eagerly parse variant-level borrow attribute instead of deferring entire Meta 2023-03-11 11:25:00 -08:00
David Tolnay 696f6f56db Merge pull request #2398 from dtolnay/borrow
Treat field-level borrow attr as duplicate of variant-level borrow attr
2023-03-11 11:24:50 -08:00
David Tolnay b7b636a23f Treat field-level borrow attr as duplicate of variant-level borrow attr 2023-03-11 11:17:40 -08:00
David Tolnay 183b91775e Fix some comments in parsing of from/try_from/into attributes 2023-03-10 14:16:11 -08:00
David Tolnay 0e70f59021 Merge pull request #2396 from dtolnay/msg
Rearrange parts of attr.rs that rustfmt has been refusing to format
2023-03-09 20:29:50 -08:00
David Tolnay 4d9b76db73 Rearrange parts of attr.rs that rustfmt has been refusing to format 2023-03-09 20:17:43 -08:00
David Tolnay 9af132f594 Factor out duplicated error messages into reused variable 2023-03-09 20:17:20 -08:00
David Tolnay 6c063569c0 Eliminate closure from Punctuated to Vec conversion 2023-03-09 00:43:33 -08:00
David Tolnay 7e9b98401d Merge pull request #2395 from dtolnay/parsewhere
Simplify parsing of where-predicates in bound attribute
2023-03-09 00:38:57 -08:00
David Tolnay f301e09e02 Simplify parsing of where-predicates in bound attribute 2023-03-09 00:20:51 -08:00
David Tolnay b80e722f81 Merge pull request #2394 from dtolnay/emptybound
Eliminate special case on empty string passed to bound=""
2023-03-08 19:53:07 -08:00
David Tolnay 1714c262c4 Eliminate special case on empty string passed to bound=""
This works just fine if we make syn parse "where " as a syn::WhereClause.

The serde(bound = "") attribute is definitely not common enough that it
would warrant a micro-optimization.
2023-03-08 19:20:06 -08:00
David Tolnay a42cdafdcd Merge pull request #2393 from dtolnay/testbound
Add a test of serde(bound = "") attribute
2023-03-08 19:19:59 -08:00
David Tolnay eb4c3f16f7 Add a test of serde(bound = "") attribute
Without serde(bound = ""), serde_derive infers a bound of `T: Serialize`
for the generated Serialize impl and `T: Deserialize<'de> + Default` for
the Deserialize impl. `X` implements none of these so the generated code
would fail to compile.

    error[E0277]: the trait bound `X: Serialize` is not satisfied
       --> test_suite/tests/test_gen.rs:268:14
        |
    268 |     assert::<PhantomDataWrapper<X>>();
        |              ^^^^^^^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `X`
        |
        = help: the following other types implement trait `Serialize`:
                  &'a T
                  &'a mut T
                  ()
                  (T0, T1)
                  (T0, T1, T2)
                  (T0, T1, T2, T3)
                  (T0, T1, T2, T3, T4)
                  (T0, T1, T2, T3, T4, T5)
                and 248 others
    note: required for `PhantomDataWrapper<X>` to implement `Serialize`
       --> test_suite/tests/test_gen.rs:262:14
        |
    262 |     #[derive(Serialize, Deserialize)]
        |              ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
    263 |     //#[serde(bound = "")]
    264 |     struct PhantomDataWrapper<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^
    note: required by a bound in `assert`
       --> test_suite/tests/test_gen.rs:767:14
        |
    767 | fn assert<T: Serialize + DeserializeOwned>() {}
        |              ^^^^^^^^^ required by this bound in `assert`
        = note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)

    error[E0277]: the trait bound `X: Deserialize<'_>` is not satisfied
       --> test_suite/tests/test_gen.rs:268:14
        |
    268 |     assert::<PhantomDataWrapper<X>>();
        |              ^^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `X`
        |
        = help: the following other types implement trait `Deserialize<'de>`:
                  <&'a Path as Deserialize<'de>>
                  <&'a [u8] as Deserialize<'de>>
                  <&'a str as Deserialize<'de>>
                  <() as Deserialize<'de>>
                  <(T0, T1) as Deserialize<'de>>
                  <(T0, T1, T2) as Deserialize<'de>>
                  <(T0, T1, T2, T3) as Deserialize<'de>>
                  <(T0, T1, T2, T3, T4) as Deserialize<'de>>
                and 331 others
    note: required for `PhantomDataWrapper<X>` to implement `for<'de> Deserialize<'de>`
       --> test_suite/tests/test_gen.rs:262:25
        |
    262 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
    263 |     //#[serde(bound = "")]
    264 |     struct PhantomDataWrapper<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^
        = note: required for `PhantomDataWrapper<X>` to implement `DeserializeOwned`
    note: required by a bound in `assert`
       --> test_suite/tests/test_gen.rs:767:26
        |
    767 | fn assert<T: Serialize + DeserializeOwned>() {}
        |                          ^^^^^^^^^^^^^^^^ required by this bound in `assert`
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

    error[E0277]: the trait bound `X: Default` is not satisfied
       --> test_suite/tests/test_gen.rs:268:14
        |
    268 |     assert::<PhantomDataWrapper<X>>();
        |              ^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `X`
        |
    note: required for `PhantomDataWrapper<X>` to implement `for<'de> Deserialize<'de>`
       --> test_suite/tests/test_gen.rs:262:25
        |
    262 |     #[derive(Serialize, Deserialize)]
        |                         ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
    263 |     //#[serde(bound = "")]
    264 |     struct PhantomDataWrapper<T> {
        |            ^^^^^^^^^^^^^^^^^^^^^
        = note: required for `PhantomDataWrapper<X>` to implement `DeserializeOwned`
    note: required by a bound in `assert`
       --> test_suite/tests/test_gen.rs:767:26
        |
    767 | fn assert<T: Serialize + DeserializeOwned>() {}
        |                          ^^^^^^^^^^^^^^^^ required by this bound in `assert`
        = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
    help: consider annotating `X` with `#[derive(Default)]`
        |
    779 | #[derive(Default)]
        |
2023-03-08 19:11:25 -08:00
David Tolnay ce86f351d6 Make a directory dedicated to regression tests
I have had a good experience with this pattern in many of my other
libraries.
2023-03-08 19:02:42 -08:00
David Tolnay 0b90f6c96a Remove the need for allow(dead_code) added by PR 2383 2023-03-08 18:59:56 -08:00
David Tolnay 2198463218 Merge pull request #2392 from dtolnay/emptylifetimes
Eliminate special case on empty string passed to borrow=""
2023-03-08 18:55:51 -08:00
David Tolnay be57a5e00a Eliminate special case on empty string passed to borrow="" 2023-03-08 18:50:19 -08:00
David Tolnay b1b09eba60 Add ui test with nonempty string containing no lifetimes 2023-03-08 18:49:59 -08:00
David Tolnay eb1e8c140d Merge pull request #2391 from dtolnay/parselifetimes
Simplify parsing of borrow="..." attributes
2023-03-08 18:44:57 -08:00
David Tolnay 43da87939d Simplify parsing of borrow="..." attributes 2023-03-08 18:38:12 -08:00
David Tolnay 06d99a13a6 Merge pull request #2390 from dtolnay/litstrparse
Replace serde_derive_internal's parse_lit_str with syn::LitStr::parse
2023-03-08 18:30:18 -08:00
David Tolnay 49a911d7de Replace serde_derive_internal's parse_lit_str with syn::LitStr::parse 2023-03-08 18:23:35 -08:00
David Tolnay 27d6628785 Refer to syn's parse result via syn instead of parse module 2023-03-08 18:20:30 -08:00
David Tolnay e4e2956e79 Handle repr attribute consistently with every other serde attribute 2023-03-08 13:57:43 -08:00
David Tolnay ea2f7b81d9 Sort symbol list in alphabetical order
PR 1916 put EXPECTING at the end instead of in order.
2023-03-08 13:14:45 -08:00
David Tolnay f0dfdb5247 Resolve wildcard_imports pedantic clippy lint in test suite
error: usage of wildcard import
       --> test_suite/tests/test_gen.rs:901:9
        |
    901 |     use super::*;
        |         ^^^^^^^^ help: try: `super::Deserialize`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports
        = note: `-D clippy::wildcard-imports` implied by `-D clippy::pedantic`
2023-03-08 12:14:04 -08:00
Max Froehlich a803ec1c1f Allow bytes for adjantly tagged enums 2023-02-18 12:49:23 -08:00
Charles-Xavier Roy f7636428ed Add check for rust version 2023-02-17 16:25:16 -05:00
Charles-Xavier Roy bd4a0981ba Enable CStr and CString in no-std enviroment 2023-02-10 09:05:24 -05:00
46 changed files with 1076 additions and 1228 deletions
-1
View File
@@ -1 +0,0 @@
test_suite/tests/expand/*.expanded.rs linguist-generated
+2 -2
View File
@@ -108,12 +108,12 @@ jobs:
- run: cd serde && cargo build
derive:
name: Rust 1.31.0
name: Rust 1.56.0
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.31.0
- uses: dtolnay/rust-toolchain@1.56.0
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
+3 -3
View File
@@ -1,13 +1,13 @@
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.19+]][Rust 1.19] [![serde_derive: rustc 1.31+]][Rust 1.31]
# Serde &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.19+]][Rust 1.19] [![serde_derive: rustc 1.56+]][Rust 1.56]
[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master
[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster
[Latest Version]: https://img.shields.io/crates/v/serde.svg
[crates.io]: https://crates.io/crates/serde
[serde: rustc 1.19+]: https://img.shields.io/badge/serde-rustc_1.19+-lightgray.svg
[serde_derive: rustc 1.31+]: https://img.shields.io/badge/serde_derive-rustc_1.31+-lightgray.svg
[serde_derive: rustc 1.56+]: https://img.shields.io/badge/serde_derive-rustc_1.56+-lightgray.svg
[Rust 1.19]: https://blog.rust-lang.org/2017/07/20/Rust-1.19.html
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
+3 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.154" # remember to update html_root_url and serde_derive dependency
version = "1.0.163" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde_derive = { version = "=1.0.154", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.163", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
@@ -27,6 +27,7 @@ doc-scrape-examples = false
features = ["derive", "rc"]
[package.metadata.docs.rs]
features = ["derive"]
targets = ["x86_64-unknown-linux-gnu"]
+11 -5
View File
@@ -78,11 +78,6 @@ fn main() {
println!("cargo:rustc-cfg=no_num_nonzero");
}
// Current minimum supported version of serde_derive crate is Rust 1.31.
if minor < 31 {
println!("cargo:rustc-cfg=no_serde_derive");
}
// TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
// stabilized in Rust 1.34:
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
@@ -94,6 +89,11 @@ fn main() {
println!("cargo:rustc-cfg=no_relaxed_trait_bounds");
}
// Current minimum supported version of serde_derive crate is Rust 1.56.
if minor < 56 {
println!("cargo:rustc-cfg=no_serde_derive");
}
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
if minor < 60 {
println!("cargo:rustc-cfg=no_target_has_atomic");
@@ -114,6 +114,12 @@ fn main() {
println!("cargo:rustc-cfg=no_std_atomic");
}
}
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
if minor < 64 {
println!("cargo:rustc-cfg=no_core_cstr");
}
}
fn rustc_minor_version() -> Option<u32> {
+12 -10
View File
@@ -666,10 +666,10 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
struct CStringVisitor;
#[cfg(feature = "std")]
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
impl<'de> Visitor<'de> for CStringVisitor {
type Value = CString;
@@ -720,7 +720,7 @@ impl<'de> Visitor<'de> for CStringVisitor {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
impl<'de> Deserialize<'de> for CString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -747,7 +747,10 @@ macro_rules! forwarded_impl {
}
}
#[cfg(all(feature = "std", not(no_de_boxed_c_str)))]
#[cfg(all(
any(feature = "std", all(not(no_core_cstr), feature = "alloc")),
not(no_de_boxed_c_str)
))]
forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str);
#[cfg(not(no_core_reverse))]
@@ -991,7 +994,8 @@ seq_impl!(
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert);
HashSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
@@ -1406,16 +1410,14 @@ macro_rules! map_impl {
}
#[cfg(any(feature = "std", feature = "alloc"))]
map_impl!(
BTreeMap<K: Ord, V>,
map,
BTreeMap::new());
map_impl!(BTreeMap<K: Ord, V>, map, BTreeMap::new());
#[cfg(feature = "std")]
map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map,
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default()));
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())
);
////////////////////////////////////////////////////////////////////////////////
+15 -4
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.154")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.163")]
// 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
@@ -219,13 +219,23 @@ mod lib {
#[cfg(feature = "std")]
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
pub use core::ffi::CStr;
#[cfg(feature = "std")]
pub use std::ffi::CStr;
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
pub use alloc::ffi::CString;
#[cfg(feature = "std")]
pub use std::ffi::CString;
#[cfg(feature = "std")]
pub use std::{error, net};
#[cfg(feature = "std")]
pub use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
pub use std::ffi::{CStr, CString, OsStr, OsString};
pub use std::ffi::{OsStr, OsString};
#[cfg(feature = "std")]
pub use std::hash::{BuildHasher, Hash};
#[cfg(feature = "std")]
@@ -328,9 +338,10 @@ mod std_error;
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
/// Derive macro available if serde is built with `features = ["derive"]`.
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
pub use serde_derive::{Deserialize, Serialize};
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
mod actually_private {
+48 -98
View File
@@ -982,9 +982,16 @@ mod content {
where
E: de::Error,
{
if field == self.tag {
self.visit_bytes(field.as_bytes())
}
fn visit_bytes<E>(self, field: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag.as_bytes() {
Ok(TagContentOtherField::Tag)
} else if field == self.content {
} else if field == self.content.as_bytes() {
Ok(TagContentOtherField::Content)
} else {
Ok(TagContentOtherField::Other)
@@ -2731,11 +2738,7 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
self.deserialize_map(visitor)
}
fn deserialize_enum<V>(
@@ -2747,17 +2750,8 @@ where
where
V: Visitor<'de>,
{
for item in self.0.iter_mut() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
};
if use_item {
let (key, value) = item.take().unwrap();
for entry in self.0.iter_mut() {
if let Some((key, value)) = flat_map_take_entry(entry, variants) {
return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
}
}
@@ -2772,7 +2766,11 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatMapAccess::new(self.0.iter()))
visitor.visit_map(FlatMapAccess {
iter: self.0.iter(),
pending_content: None,
_marker: PhantomData,
})
}
fn deserialize_struct<V>(
@@ -2784,7 +2782,12 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields))
visitor.visit_map(FlatStructAccess {
iter: self.0.iter_mut(),
pending_content: None,
fields: fields,
_marker: PhantomData,
})
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
@@ -2838,25 +2841,12 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> {
struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where
@@ -2871,6 +2861,10 @@ where
for item in &mut self.iter {
// Items in the vector are nulled out when used by a struct.
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending_content = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
@@ -2890,28 +2884,13 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatStructAccess<'a, 'de: 'a, E> {
struct FlatStructAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>,
fields: &'static [&'static str],
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: &'static [&'static str],
) -> FlatStructAccess<'a, 'de, E> {
FlatStructAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
where
@@ -2923,17 +2902,8 @@ where
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)),
};
if use_item {
let (key, content) = item.take().unwrap();
for entry in self.iter.by_ref() {
if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some);
}
@@ -2952,44 +2922,24 @@ where
}
}
/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the
/// field name matches any of the recognized ones.
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
fn flat_map_take_entry<'de>(
entry: &mut Option<(Content<'de>, Content<'de>)>,
recognized: &[&str],
) -> Option<(Content<'de>, Content<'de>)> {
// Entries in the FlatMapDeserializer buffer are nulled out as they get
// claimed for deserialization. We only use an entry if it is still present
// and if the field is one recognized by the current data structure.
let is_recognized = match entry {
None => false,
Some((k, _v)) => k.as_str().map_or(false, |name| recognized.contains(&name)),
};
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E>
where
E: Error,
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
for item in &mut self.iter {
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
if is_recognized {
entry.take()
} else {
None
}
}
+2 -2
View File
@@ -72,7 +72,7 @@ impl<'a> Serialize for fmt::Arguments<'a> {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
#[cfg(any(feature = "std", not(no_core_cstr)))]
impl Serialize for CStr {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -83,7 +83,7 @@ impl Serialize for CStr {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
impl Serialize for CString {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.154" # remember to update html_root_url
version = "1.0.163" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -11,7 +11,7 @@ keywords = ["serde", "serialization", "no_std", "derive"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.31"
rust-version = "1.56"
[features]
default = []
@@ -24,7 +24,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0.104"
syn = "2.0.3"
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
-38
View File
@@ -1,38 +0,0 @@
use std::env;
use std::process::Command;
use std::str;
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// Underscore const names stabilized in Rust 1.37:
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
if minor < 37 {
println!("cargo:rustc-cfg=no_underscore_consts");
}
// The ptr::addr_of! macro stabilized in Rust 1.51:
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
if minor < 51 {
println!("cargo:rustc-cfg=no_ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+13 -5
View File
@@ -200,10 +200,16 @@ pub fn with_bound(
for arg in &arguments.args {
match arg {
syn::GenericArgument::Type(arg) => self.visit_type(arg),
syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
syn::GenericArgument::Lifetime(_)
| syn::GenericArgument::Constraint(_)
| syn::GenericArgument::Const(_) => {}
| syn::GenericArgument::Const(_)
| syn::GenericArgument::AssocConst(_)
| syn::GenericArgument::Constraint(_) => {}
#[cfg_attr(
all(test, exhaustive),
deny(non_exhaustive_omitted_patterns)
)]
_ => {}
}
}
}
@@ -226,7 +232,9 @@ pub fn with_bound(
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
match bound {
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
syn::TypeParamBound::Lifetime(_) => {}
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
@@ -334,7 +342,7 @@ pub fn with_self_bound(
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let bound = syn::Lifetime::new(lifetime, Span::call_site());
let def = syn::LifetimeDef {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: bound.clone(),
colon_token: None,
+48 -37
View File
@@ -69,8 +69,6 @@ pub fn expand_derive_deserialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"DESERIALIZE",
ident,
impl_block,
))
}
@@ -244,9 +242,9 @@ impl BorrowedLifetimes {
}
}
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
fn de_lifetime_param(&self) -> Option<syn::LifetimeParam> {
match self {
BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeDef {
BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
@@ -419,6 +417,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
#[doc(hidden)]
struct __Visitor;
impl<'de> _serde::de::Visitor<'de> for __Visitor {
@@ -515,6 +514,7 @@ fn deserialize_tuple(
};
quote_block! {
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -605,6 +605,7 @@ fn deserialize_tuple_in_place(
let place_life = place_lifetime();
quote_block! {
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1020,6 +1021,7 @@ fn deserialize_struct(
quote_block! {
#field_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1132,6 +1134,7 @@ fn deserialize_struct_in_place(
Some(quote_block! {
#field_visitor
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1203,6 +1206,7 @@ fn prepare_enum_variant_enum(
let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
};
@@ -1275,6 +1279,7 @@ fn deserialize_externally_tagged_enum(
quote_block! {
#variant_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1522,6 +1527,7 @@ fn deserialize_adjacently_tagged_enum(
#variants_stmt
#[doc(hidden)]
struct __Seed #de_impl_generics #where_clause {
field: __Field,
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1541,6 +1547,7 @@ fn deserialize_adjacently_tagged_enum(
}
}
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1643,6 +1650,7 @@ fn deserialize_adjacently_tagged_enum(
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content];
_serde::Deserializer::deserialize_struct(
__deserializer,
@@ -1954,11 +1962,13 @@ fn deserialize_generated_identifier(
quote_block! {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field #lifetime {
#(#field_idents,)*
#ignore_variant
}
#[doc(hidden)]
struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
@@ -2046,11 +2056,13 @@ fn deserialize_custom_identifier(
None
} else if is_variant {
let variants = quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
};
Some(variants)
} else {
let fields = quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#names),* ];
};
Some(fields)
@@ -2072,6 +2084,7 @@ fn deserialize_custom_identifier(
quote_block! {
#names_const
#[doc(hidden)]
struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -2406,6 +2419,7 @@ fn deserialize_struct_as_struct_visitor(
.flat_map(|(_, _, aliases)| aliases);
quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
};
@@ -2684,6 +2698,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
let fields_stmt = {
let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
};
@@ -2864,6 +2879,7 @@ fn wrap_deserialize_with(
let delife = params.borrowed.de_lifetime();
let wrapper = quote! {
#[doc(hidden)]
struct __DeserializeWith #de_impl_generics #where_clause {
value: #value_ty,
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -3011,7 +3027,7 @@ struct InPlaceImplGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() {
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
@@ -3046,7 +3062,7 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
.into_iter()
.chain(generics.params)
.collect();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() {
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
@@ -3068,23 +3084,31 @@ struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")]
struct InPlaceTypeGenerics<'a>(&'a Parameters);
fn de_type_generics_to_tokens(
mut generics: syn::Generics,
borrowed: &BorrowedLifetimes,
tokens: &mut TokenStream,
) {
if borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
// Prepend 'de lifetime to list of generics
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens);
}
}
@@ -3097,20 +3121,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
.chain(generics.params)
.collect();
if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(generics, &self.0.borrowed, tokens);
}
}
@@ -3122,8 +3133,8 @@ impl<'a> DeTypeGenerics<'a> {
}
#[cfg(feature = "deserialize_in_place")]
fn place_lifetime() -> syn::LifetimeDef {
syn::LifetimeDef {
fn place_lifetime() -> syn::LifetimeParam {
syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'place", Span::call_site()),
colon_token: None,
+3 -19
View File
@@ -1,23 +1,11 @@
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use proc_macro2::TokenStream;
use syn;
use try;
pub fn wrap_in_const(
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
let try_replacement = try::replacement();
let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};
let use_serde = match serde_path {
Some(path) => quote! {
use #path as _serde;
@@ -31,14 +19,10 @@ pub fn wrap_in_const(
quote! {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
const _: () = {
#use_serde
#try_replacement
#code
};
}
}
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
File diff suppressed because it is too large Load Diff
+31 -32
View File
@@ -3,8 +3,8 @@ use internals::attr::{Identifier, TagType};
use internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type};
/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
// Cross-cutting checks that require looking at more than a single attrs object.
// Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_remote_generic(cx, cont);
check_getter(cx, cont);
@@ -17,18 +17,18 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_from_and_try_from(cx, cont);
}
/// Remote derive definition type must have either all of the generics of the
/// remote type:
///
/// #[serde(remote = "Generic")]
/// struct Generic<T> {…}
///
/// or none of them, i.e. defining impls for one concrete instantiation of the
/// remote type only:
///
/// #[serde(remote = "Generic<T>")]
/// struct ConcreteDef {…}
///
// Remote derive definition type must have either all of the generics of the
// remote type:
//
// #[serde(remote = "Generic")]
// struct Generic<T> {…}
//
// or none of them, i.e. defining impls for one concrete instantiation of the
// remote type only:
//
// #[serde(remote = "Generic<T>")]
// struct ConcreteDef {…}
//
fn check_remote_generic(cx: &Ctxt, cont: &Container) {
if let Some(remote) = cont.attrs.remote() {
let local_has_generic = !cont.generics.params.is_empty();
@@ -39,8 +39,8 @@ fn check_remote_generic(cx: &Ctxt, cont: &Container) {
}
}
/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
// Getters are only allowed inside structs (not enums) with the `remote`
// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.data {
Data::Enum(_) => {
@@ -62,7 +62,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
}
}
/// Flattening has some restrictions we can test.
// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) {
match &cont.data {
Data::Enum(variants) => {
@@ -101,12 +101,12 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
}
}
/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
// The `other` attribute must be used at most once and it must be the last
// variant of an enum.
//
// Inside a `variant_identifier` all variants must be unit variants. Inside a
// `field_identifier` all but possibly one variant must be unit variants. The
// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
@@ -189,8 +189,8 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
}
}
/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
// Skip-(de)serializing attributes are not allowed on variants marked
// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
@@ -264,10 +264,9 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
}
}
/// The tag of an internally-tagged struct variant must not be
/// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input.
// The tag of an internally-tagged struct variant must not be the same as either
// one of its fields, as this would result in duplicate keys in the serialized
// output and/or ambiguity in the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
@@ -313,8 +312,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
}
}
/// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason.
// In the case of adjacently-tagged enums, the type and the contents tag must
// differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match cont.attrs.tag() {
TagType::Adjacent { tag, content } => (tag, content),
@@ -332,7 +331,7 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
}
}
/// Enums and unit structs cannot be transparent.
// Enums and unit structs cannot be transparent.
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
if !cont.attrs.transparent() {
return;
+12 -5
View File
@@ -179,10 +179,13 @@ impl ReplaceReceiver<'_> {
for arg in &mut arguments.args {
match arg {
GenericArgument::Type(arg) => self.visit_type_mut(arg),
GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty),
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
GenericArgument::Lifetime(_)
| GenericArgument::Constraint(_)
| GenericArgument::Const(_) => {}
| GenericArgument::Const(_)
| GenericArgument::AssocConst(_)
| GenericArgument::Constraint(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
}
@@ -205,7 +208,9 @@ impl ReplaceReceiver<'_> {
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
match bound {
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
TypeParamBound::Lifetime(_) => {}
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
@@ -229,7 +234,9 @@ impl ReplaceReceiver<'_> {
self.visit_type_param_bound_mut(bound);
}
}
WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {}
WherePredicate::Lifetime(_) => {}
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => {}
}
}
}
+2 -1
View File
@@ -13,6 +13,7 @@ pub const DEFAULT: Symbol = Symbol("default");
pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields");
pub const DESERIALIZE: Symbol = Symbol("deserialize");
pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with");
pub const EXPECTING: Symbol = Symbol("expecting");
pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier");
pub const FLATTEN: Symbol = Symbol("flatten");
pub const FROM: Symbol = Symbol("from");
@@ -22,6 +23,7 @@ pub const OTHER: Symbol = Symbol("other");
pub const REMOTE: Symbol = Symbol("remote");
pub const RENAME: Symbol = Symbol("rename");
pub const RENAME_ALL: Symbol = Symbol("rename_all");
pub const REPR: Symbol = Symbol("repr");
pub const SERDE: Symbol = Symbol("serde");
pub const SERIALIZE: Symbol = Symbol("serialize");
pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with");
@@ -35,7 +37,6 @@ pub const TRY_FROM: Symbol = Symbol("try_from");
pub const UNTAGGED: Symbol = Symbol("untagged");
pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier");
pub const WITH: Symbol = Symbol("with");
pub const EXPECTING: Symbol = Symbol("expecting");
impl PartialEq<Symbol> for Ident {
fn eq(&self, word: &Symbol) -> bool {
+1 -1
View File
@@ -13,7 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.154")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.163")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
+7 -22
View File
@@ -97,29 +97,14 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(not(no_ptr_addr_of))]
{
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
#[cfg(no_ptr_addr_of)]
{
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
+3 -2
View File
@@ -59,8 +59,6 @@ pub fn expand_derive_serialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"SERIALIZE",
ident,
impl_block,
))
}
@@ -719,6 +717,7 @@ fn serialize_adjacently_tagged_variant(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
#[doc(hidden)]
struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -982,6 +981,7 @@ fn serialize_struct_variant_with_flatten(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
#[doc(hidden)]
struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1212,6 +1212,7 @@ fn wrap_serialize_with(
});
quote!({
#[doc(hidden)]
struct __SerializeWith #wrapper_impl_generics #where_clause {
values: (#(&'__a #field_tys, )*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.26.0" # remember to update html_root_url
version = "0.27.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals"
@@ -9,7 +9,7 @@ include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.31"
rust-version = "1.56"
[lib]
path = "lib.rs"
@@ -17,7 +17,7 @@ path = "lib.rs"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.104", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
syn = { version = "2.0", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+2 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.27.0")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
@@ -31,6 +31,7 @@
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::unused_self,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.154" # remember to update html_root_url
version = "1.0.163" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["development-tools::testing"]
+83 -95
View File
@@ -12,32 +12,29 @@ pub struct Deserializer<'de> {
tokens: &'de [Token],
}
macro_rules! assert_next_token {
($de:expr, $expected:expr) => {
match $de.next_token_opt() {
Some(token) if token == $expected => {}
Some(other) => panic!(
"expected Token::{} but deserialization wants Token::{}",
other, $expected
),
None => panic!(
"end of tokens but deserialization wants Token::{}",
$expected
),
}
};
fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
match de.next_token_opt() {
Some(token) if token == expected => Ok(()),
Some(other) => Err(de::Error::custom(format!(
"expected Token::{} but deserialization wants Token::{}",
other, expected,
))),
None => Err(de::Error::custom(format!(
"end of tokens but deserialization wants Token::{}",
expected,
))),
}
}
macro_rules! unexpected {
($token:expr) => {
panic!("deserialization did not expect this token: {}", $token)
};
fn unexpected(token: Token) -> Error {
de::Error::custom(format!(
"deserialization did not expect this token: {}",
token,
))
}
macro_rules! end_of_tokens {
() => {
panic!("ran out of tokens to deserialize")
};
fn end_of_tokens() -> Error {
de::Error::custom("ran out of tokens to deserialize")
}
impl<'de> Deserializer<'de> {
@@ -49,11 +46,8 @@ impl<'de> Deserializer<'de> {
self.tokens.first().cloned()
}
fn peek_token(&self) -> Token {
match self.peek_token_opt() {
Some(token) => token,
None => end_of_tokens!(),
}
fn peek_token(&self) -> Result<Token, Error> {
self.peek_token_opt().ok_or_else(end_of_tokens)
}
pub fn next_token_opt(&mut self) -> Option<Token> {
@@ -66,14 +60,10 @@ impl<'de> Deserializer<'de> {
}
}
fn next_token(&mut self) -> Token {
match self.tokens.split_first() {
Some((&first, rest)) => {
self.tokens = rest;
first
}
None => end_of_tokens!(),
}
fn next_token(&mut self) -> Result<Token, Error> {
let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
self.tokens = rest;
Ok(first)
}
pub fn remaining(&self) -> usize {
@@ -94,7 +84,7 @@ impl<'de> Deserializer<'de> {
len: len,
end: end,
})?;
assert_next_token!(self, end);
assert_next_token(self, end)?;
Ok(value)
}
@@ -112,7 +102,7 @@ impl<'de> Deserializer<'de> {
len: len,
end: end,
})?;
assert_next_token!(self, end);
assert_next_token(self, end)?;
Ok(value)
}
}
@@ -129,7 +119,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
let token = self.next_token();
let token = self.next_token()?;
match token {
Token::Bool(v) => visitor.visit_bool(v),
Token::I8(v) => visitor.visit_i8(v),
@@ -161,50 +151,50 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => {
let variant = self.next_token();
let next = self.peek_token();
let variant = self.next_token()?;
let next = self.peek_token()?;
match (variant, next) {
(Token::Str(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_str(variant)
}
(Token::BorrowedStr(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_borrowed_str(variant)
}
(Token::String(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_string(variant.to_string())
}
(Token::Bytes(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_bytes(variant)
}
(Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_borrowed_bytes(variant)
}
(Token::ByteBuf(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_byte_buf(variant.to_vec())
}
(Token::U8(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u8(variant)
}
(Token::U16(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u16(variant)
}
(Token::U32(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u32(variant)
}
(Token::U64(variant), Token::Unit) => {
self.next_token();
self.next_token()?;
visitor.visit_u64(variant)
}
(variant, Token::Unit) => unexpected!(variant),
(variant, Token::Unit) => Err(unexpected(variant)),
(variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
}
@@ -232,9 +222,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
| Token::MapEnd
| Token::StructEnd
| Token::TupleVariantEnd
| Token::StructVariantEnd => {
unexpected!(token);
}
| Token::StructVariantEnd => Err(unexpected(token)),
}
}
@@ -242,13 +230,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit | Token::None => {
self.next_token();
self.next_token()?;
visitor.visit_none()
}
Token::Some => {
self.next_token();
self.next_token()?;
visitor.visit_some(self)
}
_ => self.deserialize_any(visitor),
@@ -264,9 +252,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Enum { name: n } if name == n => {
self.next_token();
self.next_token()?;
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
@@ -286,9 +274,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
_ => self.deserialize_any(visitor),
@@ -303,9 +291,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::NewtypeStruct { .. } => {
assert_next_token!(self, Token::NewtypeStruct { name: name });
assert_next_token(self, Token::NewtypeStruct { name: name })?;
visitor.visit_newtype_struct(self)
}
_ => self.deserialize_any(visitor),
@@ -316,21 +304,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit | Token::UnitStruct { .. } => {
self.next_token();
self.next_token()?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -346,25 +334,25 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Unit => {
self.next_token();
self.next_token()?;
visitor.visit_unit()
}
Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name });
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token();
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { len: n, .. } => {
assert_next_token!(self, Token::TupleStruct { name: name, len: n });
assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -380,13 +368,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
match self.peek_token() {
match self.peek_token()? {
Token::Struct { len: n, .. } => {
assert_next_token!(self, Token::Struct { name: name, len: n });
assert_next_token(self, Token::Struct { name: name, len: n })?;
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
}
Token::Map { .. } => {
self.next_token();
self.next_token()?;
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
}
_ => self.deserialize_any(visitor),
@@ -476,7 +464,7 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: DeserializeSeed<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. }
@@ -497,9 +485,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token() {
match self.de.peek_token()? {
Token::UnitVariant { .. } => {
self.de.next_token();
self.de.next_token()?;
Ok(())
}
_ => Deserialize::deserialize(self.de),
@@ -510,9 +498,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
T: DeserializeSeed<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::NewtypeVariant { .. } => {
self.de.next_token();
self.de.next_token()?;
seed.deserialize(self.de)
}
_ => seed.deserialize(self.de),
@@ -523,26 +511,26 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: Visitor<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if len == enum_len {
self.de
.visit_seq(Some(len), Token::TupleVariantEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
Token::Seq {
len: Some(enum_len),
} => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if len == enum_len {
self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -557,27 +545,27 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where
V: Visitor<'de>,
{
match self.de.peek_token() {
match self.de.peek_token()? {
Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
Token::Map {
len: Some(enum_len),
} => {
let token = self.de.next_token();
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::MapEnd, visitor)
} else {
unexpected!(token);
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -622,7 +610,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
.deserialize(BytesDeserializer { value: variant })
.map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other),
Some(other) => Err(unexpected(other)),
None => Ok(None),
}
}
@@ -641,7 +629,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
};
seed.deserialize(SeqAccessDeserializer::new(visitor))?
};
assert_next_token!(self.de, Token::TupleVariantEnd);
assert_next_token(self.de, Token::TupleVariantEnd)?;
Ok(value)
}
EnumFormat::Map => {
@@ -653,7 +641,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
};
seed.deserialize(MapAccessDeserializer::new(visitor))?
};
assert_next_token!(self.de, Token::StructVariantEnd);
assert_next_token(self.de, Token::StructVariantEnd)?;
Ok(value)
}
EnumFormat::Any => seed.deserialize(&mut *self.de),
+1 -5
View File
@@ -140,7 +140,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.154")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.163")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
@@ -182,7 +182,3 @@ pub use assert::{
pub use token::Token;
pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
+6 -8
View File
@@ -63,14 +63,12 @@ macro_rules! assert_next_token {
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
Some(expected) => {
panic!("expected Token::{} but serialized as {}",
expected, $actual);
}
None => {
panic!("expected end of tokens, but {} was serialized",
$actual);
}
Some(expected) => return Err(ser::Error::custom(
format!("expected Token::{} but serialized as {}", expected, $actual)
)),
None => return Err(ser::Error::custom(
format!("expected end of tokens, but {} was serialized", $actual)
)),
}
};
}
+1
View File
@@ -12,6 +12,7 @@ unstable = ["serde/unstable"]
serde = { path = "../serde" }
[dev-dependencies]
automod = "1.0"
fnv = "1.0"
rustversion = "1.0"
serde = { path = "../serde", features = ["rc", "derive"] }
+3
View File
@@ -0,0 +1,3 @@
mod regression {
automod::dir!("tests/regression");
}
+43
View File
@@ -0,0 +1,43 @@
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Nested;
#[derive(Deserialize)]
pub enum ExternallyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(tag = "tag")]
pub enum InternallyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
pub enum AdjacentlyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum UntaggedWorkaround {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
+11
View File
@@ -0,0 +1,11 @@
use serde::Deserialize;
macro_rules! bug {
($serde_path:literal) => {
#[derive(Deserialize)]
#[serde(crate = $serde_path)]
pub struct Struct;
};
}
bug!("serde");
+5
View File
@@ -0,0 +1,5 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde()]
pub struct S;
+47
View File
@@ -2317,6 +2317,53 @@ fn test_internally_tagged_enum_new_type_with_unit() {
);
}
#[test]
fn test_adjacently_tagged_enum_bytes() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A { a: i32 },
}
let data = Data::A { a: 0 };
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
assert_de_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Bytes(b"t"),
Token::Str("A"),
Token::Bytes(b"c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
}
#[test]
fn test_adjacently_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
+17 -13
View File
@@ -4,6 +4,8 @@
clippy::used_underscore_binding
)]
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
use serde::de::IntoDeserializer;
use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
@@ -130,20 +132,22 @@ fn test_cow() {
borrowed: Cow<'b, str>,
}
let tokens = &[
Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"),
Token::BorrowedStr("copied"),
Token::Str("borrowed"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
];
struct BorrowedStr(&'static str);
let mut de = serde_test::Deserializer::new(tokens);
let cows = Cows::deserialize(&mut de).unwrap();
impl<'de> IntoDeserializer<'de> for BorrowedStr {
type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>;
fn into_deserializer(self) -> Self::Deserializer {
BorrowedStrDeserializer::new(self.0)
}
}
let de = MapDeserializer::new(IntoIterator::into_iter([
("copied", BorrowedStr("copied")),
("borrowed", BorrowedStr("borrowed")),
]));
let cows = Cows::deserialize(de).unwrap();
match cows.copied {
Cow::Owned(ref s) if s == "copied" => {}
+17 -23
View File
@@ -33,7 +33,7 @@ use std::time::{Duration, UNIX_EPOCH};
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher;
use serde::de::DeserializeOwned;
use serde::de::{DeserializeOwned, IntoDeserializer};
use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, Configure, Token};
@@ -202,9 +202,8 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
.chain(vec![Token::MapEnd].into_iter())
.collect();
let mut de = serde_test::Deserializer::new(&concated_tokens);
let base = IgnoreBase::deserialize(&mut de).unwrap();
assert_eq!(base, IgnoreBase { a: 1 });
let expected = IgnoreBase { a: 1 };
assert_de_tokens(&expected, &concated_tokens);
}
//////////////////////////////////////////////////////////////////////////
@@ -2245,39 +2244,34 @@ fn test_cstr() {
#[test]
fn test_atomics() {
fn test<L, A, T>(load: L, val: T, token: Token)
fn test<L, A, T>(load: L, val: T)
where
L: Fn(&A, Ordering) -> T,
A: DeserializeOwned,
T: PartialEq + Debug,
T: PartialEq + Debug + Copy + for<'de> IntoDeserializer<'de>,
{
let tokens = &[token];
let mut de = serde_test::Deserializer::new(tokens);
match A::deserialize(&mut de) {
match A::deserialize(val.into_deserializer()) {
Ok(v) => {
let loaded = load(&v, Ordering::Relaxed);
assert_eq!(val, loaded);
}
Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
}
}
test(AtomicBool::load, true, Token::Bool(true));
test(AtomicI8::load, -127, Token::I8(-127i8));
test(AtomicI16::load, -510, Token::I16(-510i16));
test(AtomicI32::load, -131072, Token::I32(-131072i32));
test(AtomicIsize::load, -131072isize, Token::I32(-131072));
test(AtomicU8::load, 127, Token::U8(127u8));
test(AtomicU16::load, 510u16, Token::U16(510u16));
test(AtomicU32::load, 131072u32, Token::U32(131072u32));
test(AtomicUsize::load, 131072usize, Token::U32(131072));
test(AtomicBool::load, true);
test(AtomicI8::load, -127i8);
test(AtomicI16::load, -510i16);
test(AtomicI32::load, -131072i32);
test(AtomicIsize::load, -131072isize);
test(AtomicU8::load, 127u8);
test(AtomicU16::load, 510u16);
test(AtomicU32::load, 131072u32);
test(AtomicUsize::load, 131072usize);
#[cfg(target_arch = "x86_64")]
{
test(AtomicI64::load, -8589934592, Token::I64(-8589934592));
test(AtomicU64::load, 8589934592u64, Token::U64(8589934592));
test(AtomicI64::load, -8589934592i64);
test(AtomicU64::load, 8589934592u64);
}
}
+10 -50
View File
@@ -257,6 +257,16 @@ fn test_gen() {
}
assert::<VariantWithTraits2<X, X>>();
type PhantomDataAlias<T> = PhantomData<T>;
#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
struct PhantomDataWrapper<T> {
#[serde(default)]
field: PhantomDataAlias<T>,
}
assert::<PhantomDataWrapper<X>>();
#[derive(Serialize, Deserialize)]
struct CowStr<'a>(Cow<'a, str>);
assert::<CowStr>();
@@ -892,53 +902,3 @@ pub struct RemotePackedNonCopyDef {
impl Drop for RemotePackedNonCopyDef {
fn drop(&mut self) {}
}
//////////////////////////////////////////////////////////////////////////
/// Regression tests for <https://github.com/serde-rs/serde/issues/2371>
#[allow(dead_code)]
mod static_and_flatten {
use super::*;
#[derive(Deserialize)]
struct Nested;
#[derive(Deserialize)]
enum ExternallyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
enum AdjacentlyTagged {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
#[derive(Deserialize)]
#[serde(untagged)]
enum UntaggedWorkaround {
Flatten {
#[serde(flatten)]
nested: Nested,
string: &'static str,
},
}
}
@@ -1,5 +1,5 @@
error: duplicate serde attribute `borrow`
--> tests/ui/borrow/duplicate_variant.rs:8:13
--> tests/ui/borrow/duplicate_variant.rs:9:15
|
8 | #[serde(borrow)]
| ^^^^^^
9 | S(#[serde(borrow)] Str<'a>),
| ^^^^^^
@@ -3,6 +3,8 @@ use serde_derive::Deserialize;
#[derive(Deserialize)]
struct Test<'a> {
#[serde(borrow = "")]
r: &'a str,
#[serde(borrow = " ")]
s: &'a str,
}
@@ -3,3 +3,9 @@ error: at least one lifetime must be borrowed
|
5 | #[serde(borrow = "")]
| ^^
error: at least one lifetime must be borrowed
--> tests/ui/borrow/empty_lifetimes.rs:7:22
|
7 | #[serde(borrow = " ")]
| ^^^^
+1 -1
View File
@@ -1,4 +1,4 @@
error: unexpected end of input, expected literal
error: unexpected end of input, expected an expression
--> tests/ui/malformed/cut_off.rs:4:17
|
4 | #[serde(rename =)]
@@ -1,11 +1,11 @@
error: expected #[serde(...)]
error: expected attribute arguments in parentheses: #[serde(...)]
--> tests/ui/malformed/not_list.rs:4:3
|
4 | #[serde]
| ^^^^^
error: expected #[serde(...)]
--> tests/ui/malformed/not_list.rs:5:3
error: expected parentheses: #[serde(...)]
--> tests/ui/malformed/not_list.rs:5:9
|
5 | #[serde = "?"]
| ^^^^^^^^^^^
| ^
@@ -0,0 +1,9 @@
use serde_derive::Serialize;
#[derive(Serialize)]
struct S {
#[serde(skip_serializing_if, x.is_empty())]
x: Vec<()>,
}
fn main() {}
@@ -0,0 +1,5 @@
error: expected `=`
--> tests/ui/malformed/trailing_expr.rs:5:32
|
5 | #[serde(skip_serializing_if, x.is_empty())]
| ^
@@ -1,4 +1,4 @@
error: unexpected literal in serde container attribute
error: unexpected literal in nested attribute, expected ident
--> tests/ui/unexpected-literal/container.rs:4:9
|
4 | #[serde("literal")]
@@ -1,4 +1,4 @@
error: unexpected literal in serde field attribute
error: unexpected literal in nested attribute, expected ident
--> tests/ui/unexpected-literal/field.rs:5:13
|
5 | #[serde("literal")]
@@ -1,4 +1,4 @@
error: unexpected literal in serde variant attribute
error: unexpected literal in nested attribute, expected ident
--> tests/ui/unexpected-literal/variant.rs:5:13
|
5 | #[serde("literal")]