Compare commits

...

142 Commits

Author SHA1 Message Date
David Tolnay 43a9f59c18 Release 1.0.103 2019-11-24 16:15:13 -08:00
David Tolnay ff70409215 Merge pull request #1669 from H2CO3/master
Allow untagged unit variants to deserialize from `Visitor::visit_none()`
2019-11-24 16:13:37 -08:00
David Tolnay 97a98a7031 Test only deser for untagged unit visit_none 2019-11-24 15:59:08 -08:00
David Tolnay 533fb9cc44 Remove never_type feature gate
The stabilization for this feature has landed in nightly.
2019-11-23 19:30:39 -08:00
Árpád Goretity 59b99d2d60 Move test for untagged-variant-from-unit where it belongs 2019-11-07 21:18:12 +01:00
Árpád Goretity c796daed7c Fix test for untagged unit variant 2019-11-07 12:58:09 +01:00
Árpád Goretity 6e2c385fa5 Allow untagged unit variants to deserialize from Visitor::visit_none() 2019-11-06 17:31:27 +01:00
David Tolnay 4eb580790d Require serde_derive version to be the same as serde version
Without this, Cargo could combine new serde_derive with old serde
resulting in generated code that refers to types that don't exist yet in
the serde version.
2019-11-02 15:17:09 -07:00
David Tolnay a2c83d754b Merge pull request #1664 from mathstuf/minimal-versions-compat
serde_derive: require the same version as serde
2019-11-02 12:04:20 -07:00
Ben Boeckel 6f946b20ec serde_derive: require the same version as serde
This ensures that all features supported by serde are always available
through the derive macro provided through the feature flag.

Fixes: #1647
2019-11-01 19:47:31 -04:00
David Tolnay 2ceabad360 Release 1.0.102 2019-10-27 13:39:27 -07:00
David Tolnay a00aee1495 Use a dedicated cfg for PathBuf::into_boxed_path 2019-10-27 13:38:25 -07:00
David Tolnay 4e31c9984d Merge pull request #1656 from heftig/path-improvements
Improve Path deserialization
2019-10-27 13:37:12 -07:00
Jan Alexander Steffens (heftig) b8772a1e40 Deserialize Box<Path> through PathBuf::into_boxed_path
Including Rc<Path> et al.

Fixes https://github.com/serde-rs/serde/issues/1633
2019-10-22 22:31:51 +02:00
Jan Alexander Steffens (heftig) 42990d8264 Deserialize PathBuf from bytes
&Path already allows this. Also complete the tests for Path/PathBuf.
2019-10-22 22:30:53 +02:00
David Tolnay cf31418555 Resolve unused_self lint 2019-10-17 11:05:30 -04:00
David Tolnay 5db72b8ad9 Ignore must_use_candidate pedantic lint 2019-10-17 11:05:28 -04:00
David Tolnay fe8f8bcf7b Address needless_doctest_main lint in serde_test 2019-10-08 21:23:17 -07:00
David Tolnay d4d737de8d Resolve redundant_clone lint 2019-10-08 21:16:45 -07:00
David Tolnay 52f6e96ee8 Ignore needless_doctest_main lint 2019-10-08 21:15:08 -07:00
David Tolnay 44fa7b0f6b Remove unused rustc-serialize dependency from test suite 2019-10-04 21:29:06 -04:00
David Tolnay bda561df4e Update test suite to nightly-2019-10-04 2019-10-03 21:45:09 -04:00
David Tolnay 8955420baf Update test suite to nightly-2019-10-02 2019-10-02 09:45:00 -04:00
David Tolnay 21ee256911 Update test suite to nightly-2019-09-30 2019-09-30 15:56:04 -04:00
David Tolnay 4aba6fae78 Release 1.0.101 2019-09-16 00:32:28 -07:00
David Tolnay fe06bc2f88 More concise explanation of allow(unused_variables) 2019-09-16 00:31:23 -07:00
David Tolnay 8dfb4cd02f Merge pull request #1617 from arilotter/master
Fix unused variable warning when field of adjacently tagged enum is skipped
2019-09-15 23:51:39 -07:00
David Tolnay d1ade37827 Ignore new too_many_lines lint 2019-09-10 23:15:59 -07:00
Ari Lotter 9de49241fb Bug fix for #1610
Allow unused variables in tuple in AdjacentlyTagged serializer
2019-09-09 10:43:05 -04:00
David Tolnay b24d50160a Remove use of ref keyword from serde_derive 2019-09-07 23:16:02 -07:00
David Tolnay e46463e69f Add tests for attribute parse errors 2019-09-07 22:57:27 -07:00
David Tolnay a3157c9572 Produce errors on attr that fails to parse as Meta 2019-09-07 22:46:50 -07:00
David Tolnay 0d4722680a Use flatten() to iterate serde meta items 2019-09-07 22:44:25 -07:00
David Tolnay 7ab12597bb Un-wrap error message strings for better grepping 2019-09-07 22:40:24 -07:00
David Tolnay b86a46c83c Factor skipping in newtype variants into effective_style 2019-09-07 22:16:56 -07:00
David Tolnay 187a0a3ec0 Format with rustfmt 2019-08-19 2019-09-07 22:16:49 -07:00
David Tolnay 111c18dec3 Merge pull request #1622 from Xaeroxe/fix-new-types
Fix (de)serialization of new types where the internal type is skipped
2019-09-07 22:16:40 -07:00
David Tolnay 7a2b137912 Reuse span in default deserialize_with path for Cows 2019-09-07 20:24:59 -07:00
David Tolnay 791b9fbe81 Release serde_derive_internals 2019-09-07 20:14:30 -07:00
David Tolnay 0fdc0257aa Sort Postcard in the same order as on the website 2019-09-07 19:10:48 -07:00
David Tolnay b6a77c4413 Release 1.0.100 2019-09-07 18:55:50 -07:00
David Tolnay 33438850a6 Merge pull request #1620 from dtolnay/error
Export std error type so no_std data formats don't need a "std" feature
2019-09-07 18:54:34 -07:00
Jake Kiesel fcbb3d3783 Add support for other enum representations 2019-09-07 11:43:53 -06:00
Jake Kiesel acc8640c1e Fix (de)serialization of new types where the internal type is skipped 2019-09-07 03:20:43 -06:00
David Tolnay c083cfd65e Export std error type so downstream doesn't need "std" feature 2019-09-04 20:20:36 -07:00
David Tolnay 4cea81f93f Merge pull request #1615 from jamesmunns/patch-1
Add Postcard to the list of Serde Data Formats
2019-08-28 10:17:43 -07:00
James Munns 2d36be753a Add Postcard to the list of Serde Data Formats 2019-08-28 12:23:54 +02:00
David Tolnay 738d29eaa9 Update serde_derive_internals to syn 1.0 2019-08-26 12:29:45 -07:00
David Tolnay b536fb67a4 Merge pull request #1604 from UnHumbleBen/patch-1
Fixed a typo
2019-08-19 03:10:49 -07:00
Benjamin Lee b10c23a950 Fixed a typo 2019-08-18 22:37:28 -07:00
David Tolnay 85a5cf7cb1 Document serde_derive minimum rustc 2019-08-18 18:31:40 -07:00
David Tolnay 192f5cd647 Release 1.0.99 2019-08-16 11:50:19 -07:00
David Tolnay 7dceee64fe Merge pull request #1591 from dtolnay/up
Update to syn/quote 1.0
2019-08-16 11:49:33 -07:00
David Tolnay 8ad6ae71c6 Update serde_derive minimum rustc version to 1.31 2019-08-16 11:31:15 -07:00
David Tolnay 3ea85a28cf Update to syn/quote 1.0 2019-08-16 11:31:15 -07:00
David Tolnay 273ecdb786 Update ui tests on nightly-2019-08-16 2019-08-16 11:30:49 -07:00
David Tolnay de40eb7306 Update serde_derive to use question mark 2019-08-16 11:28:25 -07:00
David Tolnay b9c44073ce Update serde_test to use question mark 2019-08-16 11:25:12 -07:00
David Tolnay d6e5947ad2 Suppress warnings about try! macro 2019-08-16 11:24:22 -07:00
David Tolnay 668651ee01 Format with rustfmt 2019-07-30 2019-07-31 21:19:46 -07:00
David Tolnay fb1cacc10e Update Attr structs to hold symbols 2019-07-31 21:06:36 -07:00
David Tolnay 735e56c26f Use symbols when parsing values out of attribute 2019-07-31 21:06:36 -07:00
David Tolnay 97de3dccbb Factor out attr symbols into constants 2019-07-31 21:06:36 -07:00
David Tolnay 690467cbe2 Release 1.0.98 2019-07-28 10:33:34 -07:00
David Tolnay 71efd8ffda Merge pull request #1590 from dtolnay/manifest
Work around failing to parse manifest in 1.27 and 1.28 builds
2019-07-28 10:32:14 -07:00
David Tolnay 9bb196ae6e Work around failing to parse manifest in 1.27 and 1.28 builds 2019-07-28 10:07:15 -07:00
David Tolnay ce75418e40 Merge pull request #1589 from Flaise/nonzeroi
Add support for NonZeroI* types
2019-07-28 10:02:09 -07:00
Flaise 78c7f09e28 Add build gate for nonzero signed integers so rustc <1.34 still works 2019-07-28 11:44:31 -05:00
David Tolnay e7269ac84e Add travis builds on every version in build.rs 2019-07-28 08:36:06 -07:00
Flaise 34866e20a8 Add support for NonZeroI* types 2019-07-28 09:12:29 -05:00
David Tolnay 3ae2bee272 Release 1.0.97 2019-07-17 14:56:51 -07:00
David Tolnay d0fb958e99 Remove unneeded explicit type parameters in test_from_into_traits 2019-07-17 12:32:34 -07:00
David Tolnay b941c63a53 More typical TryFrom usage for test 2019-07-17 12:31:41 -07:00
David Tolnay cf70c3fb05 Format with rustfmt 2019-06-09 2019-07-17 12:27:26 -07:00
David Tolnay f249e72162 Provide try_from only on 1.34+ 2019-07-17 12:21:18 -07:00
David Tolnay 92e0b62c6b Merge pull request 1526 from fanzeyi/try_from 2019-07-17 12:16:31 -07:00
David Tolnay cf32a5b204 Release 1.0.96 2019-07-17 12:04:19 -07:00
David Tolnay 7b0e06c825 Provide 32 bit atomic impls for emscripten 2019-07-17 11:44:24 -07:00
David Tolnay 3158bf9093 Merge pull request #1581 from Roguelazer/issue-1579
conservatively limit atomic features
2019-07-17 11:01:21 -07:00
James Brown 01fade764c replaced one too many _ with - 2019-07-17 09:57:53 -07:00
James Brown 210c2419be conservatively limit atomic features 2019-07-17 09:19:03 -07:00
David Tolnay da05163d51 Release 1.0.95 2019-07-16 10:08:53 -07:00
David Tolnay f3e2bb5104 Disable 64 bit atomic tests on emscripten 2019-07-16 10:00:44 -07:00
David Tolnay 7a4c1086b5 Emscripten does not have 64 bit atomics 2019-07-16 09:57:00 -07:00
David Tolnay e89feb9635 Test atomics without needing a macro
As a secondary benefit, this avoids a congnitive_complexity lint from
Clippy.
2019-07-16 09:17:36 -07:00
David Tolnay 5f72766c27 Ignore unreadable_literal lint in test code 2019-07-16 09:04:43 -07:00
David Tolnay 85ae57040d One macro to deserialize all atomics 2019-07-16 07:46:44 -07:00
David Tolnay d55a4a279f Deserialize atomics without needing element type 2019-07-16 07:45:41 -07:00
David Tolnay bee9299693 One macro to serialize all atomics 2019-07-16 07:42:42 -07:00
David Tolnay 9529fcec96 Serialize atomics using the primitive's Serialize impl 2019-07-16 07:40:37 -07:00
David Tolnay bcec168e23 Centralize atomic imports 2019-07-16 07:36:16 -07:00
David Tolnay 102a332616 Format with rustfmt 2019-06-09 2019-07-16 07:32:13 -07:00
David Tolnay a280942f02 Add a builder on 1.34 to cover atomic types 2019-07-16 07:29:10 -07:00
David Tolnay 637dba5c2a Merge pull request #1572 from Roguelazer/issue-1496
Implement serialization and deserialization for std::sync::atomic types
2019-07-16 07:28:18 -07:00
David Tolnay 24f292d081 Build alloc feature on 1.36 in travis 2019-07-16 07:22:47 -07:00
David Tolnay fa5c99e48a Alloc crate is no longer unstable 2019-07-16 07:21:09 -07:00
David Tolnay 48f1a2c9b2 Merge pull request #1576 from c410-f3r/alloc-feature
Make `alloc` feature work on stable
2019-07-16 07:19:49 -07:00
Caio 50ebbd63c6 Enable alloc on stable 2019-07-15 14:24:03 -03:00
James Brown 4e5f63ff45 gate atomic serde on rust 1.34 or higher 2019-07-12 13:44:42 -07:00
James Brown de709e72a8 implement deserialization for atomic integer types 2019-07-11 18:18:54 -07:00
James Brown 56d3c8f071 implement serialization for atomic integer types 2019-07-11 17:34:53 -07:00
David Tolnay ce89adecc1 Suppress deprecation warning on mem::uninitialized 2019-07-07 21:19:50 -07:00
David Tolnay bc7a85063d Switch to rustversion 2019-07-07 21:14:11 -07:00
David Tolnay 0574f1e020 Merge pull request #1561 from BurntSushi/ag/update-i128-docs
Update docs for serde_if_integer128
2019-07-01 15:04:54 -07:00
Andrew Gallant f9fdd60e2e Update docs for serde_if_integer128
The docs imply that the only consideration for using the
serde_if_integer128 macro is support for older versions of Rust, but
Serde's build configuration for 128-bit integers is also gated on the
target platform. For example, if Serde is being compiled for an
emscripten target, then it will not provide 128-bit integer APIs.

See also: https://github.com/BurntSushi/rust-csv/issues/158
2019-07-01 10:18:57 -04:00
David Tolnay 1c1eecabc0 Release 1.0.94 2019-06-27 10:55:12 -07:00
David Tolnay abd3fd004e Merge pull request #1559 from dtolnay/ignore-enum
Accept enums in IgnoredAny
2019-06-27 10:54:22 -07:00
David Tolnay 15ee353488 IgnoredAny::visit_enum for old compilers 2019-06-27 10:45:18 -07:00
David Tolnay e75efbfd31 Support ignoring enum with IgnoredAny 2019-06-27 10:29:55 -07:00
David Tolnay 1c97a7ecb3 Add comprehensive test for deserializing IgnoredAny from enum 2019-06-27 10:23:39 -07:00
David Tolnay fccd3e9fba Add deserialization tests for IgnoredAny 2019-06-27 10:07:06 -07:00
David Tolnay 4cb13b33e0 Release 1.0.93 2019-06-23 12:50:17 -07:00
David Tolnay 629802f2ab Merge pull request #1555 from serde-rs/int
Allow integer key in untagged flattened map
2019-06-23 12:49:21 -07:00
David Tolnay afb1754528 Allow integer key in untagged flattened map 2019-06-23 12:09:15 -07:00
David Tolnay dbd67c6c89 Clippy const_static_lifetime lint has been renamed 2019-06-19 01:34:13 -07:00
David Tolnay ed01bdb9dd Remove fixed cast_precision_loss lint 2019-06-15 10:13:05 -07:00
David Tolnay b54821d8ab Alloc feature has been stabilized
warning: the feature `alloc` has been stable since 1.36.0 and no longer requires an attribute to enable
      --> serde/src/lib.rs:84:40
       |
    84 | #![cfg_attr(feature = "alloc", feature(alloc))]
       |                                        ^^^^^
       |
       = note: #[warn(stable_features)] on by default
2019-05-31 21:26:43 -07:00
David Tolnay 89c6a79b6e Suppress a new pedantic lint 2019-05-31 21:25:36 -07:00
David Tolnay cd0412bddc Release 1.0.92 2019-05-31 13:44:01 -07:00
David Tolnay e42262f0f5 Provide ToString for re-export by serde::export 2019-05-31 13:42:22 -07:00
David Tolnay 0a3eeab273 Merge pull request #1543 from jplatte/alloc-de-compile-fix
Fix a compile error in derive(Deserialize) with no_std + alloc
2019-05-31 13:41:07 -07:00
Jonas Platte e4e110e28f Fix a compile error in derive(Deserialize) with no_std + alloc 2019-05-31 22:16:40 +02:00
David Tolnay 0726623389 Ignore bare_trait_objects lint to support old compilers 2019-05-31 11:34:18 -07:00
David Tolnay fd9d334d01 Smaller format for license section 2019-05-18 17:35:47 -07:00
David Tolnay 840eb14121 Merge pull request #1528 from est31/no_variable_names
Don't use variable names
2019-05-17 08:57:14 -07:00
est31 8fef196ee4 Don't use variable names
They aren't needed. This makes the macro a bit simpler
2019-05-17 16:50:41 +02:00
David Tolnay 9c756f1ec0 Disable ui tests on emscripten
These hit a strange error in our Emscripten builder in Travis as well as
locally through cargo web:

    ERROR: failed to execute cargo: Resource temporarily unavailable (os error 11)
2019-05-12 00:28:22 -07:00
Zeyi Fan 4c29eea790 add attribute try_from 2019-05-11 23:31:24 -07:00
David Tolnay 6dd2b4607f Switch to SPDX 2.1 license expression 2019-05-09 15:21:20 -07:00
David Tolnay 1e9ae88f53 Work around "failed to select a version for serde_test_suite"
Without this:

    error: failed to select a version for `serde_test_suite`.
        ... required by package `serde_test_suite-tests v0.0.0`
    versions that meet the requirements `= 0.0.0` are: 0.0.0

    the package `serde_test_suite-tests` depends on `serde_test_suite`, with features: `serde` but `serde_test_suite` does not have these features.

    failed to select a version for `serde_test_suite` which could resolve this conflict

Seems like a Cargo bug -- I will minimize and report.
2019-05-06 22:53:38 -07:00
David Tolnay 5cc3902ab9 Release 1.0.91 2019-05-06 16:27:04 -07:00
David Tolnay c8e09e2d6d Merge pull request #1522 from dtolnay/enum
Support deserializing enum out of MapAccessDeserializer
2019-05-06 16:26:43 -07:00
David Tolnay e2a2ba116c Remove old instructions intended for compiletest 2019-05-06 16:17:30 -07:00
David Tolnay 0a9d24a218 Support deserializing enum out of MapAccessDeserializer 2019-05-06 16:11:28 -07:00
David Tolnay c222183669 Merge pull request #1521 from serde-rs/trybuild
Switch ui tests to trybuild
2019-05-06 10:44:25 -07:00
David Tolnay 140f9beee7 Switch ui tests to trybuild 2019-05-06 10:25:47 -07:00
David Tolnay 28ce892617 Disable compiletest in appveyor
error[E0464]: multiple matching crates for `serde`
      --> $DIR/wrong_getter.rs:15:10
       |
    15 | #[derive(Serialize)]
       |          ^^^^^^^^^
       |
       = note: candidates:
               crate `serde`: /?/C:/projects/serde/test_suite/deps/target/debug/deps/libserde-a1a28acc73b0edde.rlib
               crate `serde`: /?/C:/Users/appveyor/.
2019-04-22 23:18:21 -07:00
David Tolnay 1e6d3ff99b Merge pull request #1512 from dtolnay/off
Temporarily disable compiletest testing in CI
2019-04-22 23:05:54 -07:00
David Tolnay fba1b92cbf Temporarily disable compiletest testing in CI
The nightly compiler just added a dependency on serde so libserde ends
up in the sysroot, breaking crate resolution inside of compiletest. We
will need to figure out how else to run these tests.

    error[E0464]: multiple matching crates for `serde`
      --> $DIR/wrong_ser.rs:9:10
       |
     9 | #[derive(Serialize)]
       |          ^^^^^^^^^
       |
       = note: candidates:
               crate `serde`: /rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libserde-2b75907288aa7c40.rlib
               crate `serde`: /serde/test_suite/deps/target/debug/deps/libserde-33e0a319242344ce.rlib
2019-04-22 22:42:36 -07:00
David Tolnay ce1686379d Update test suite to nightly-2019-04-20 2019-04-19 22:54:59 -07:00
David Tolnay 79a20e9e33 Resolve option_map_unwrap_or_else lint 2019-04-10 22:57:47 -07:00
David Tolnay e9cd73f78e Remove link to hjson
This project has still not been updated to Serde 1.0.
2019-04-08 10:39:55 -07:00
150 changed files with 2015 additions and 1497 deletions
+20 -8
View File
@@ -26,10 +26,8 @@ matrix:
- cargo build --no-default-features --features alloc - cargo build --no-default-features --features alloc
- cargo build --no-default-features --features rc,alloc - cargo build --no-default-features --features rc,alloc
- cargo test --features derive,rc,unstable - cargo test --features derive,rc,unstable
- cd "${TRAVIS_BUILD_DIR}/test_suite/deps"
- cargo build
- cd "${TRAVIS_BUILD_DIR}/test_suite" - cd "${TRAVIS_BUILD_DIR}/test_suite"
- cargo test --features compiletest,unstable - cargo test --features unstable
- cd "${TRAVIS_BUILD_DIR}/test_suite/no_std" - cd "${TRAVIS_BUILD_DIR}/test_suite/no_std"
- cargo build - cargo build
@@ -41,16 +39,30 @@ matrix:
- cd "${TRAVIS_BUILD_DIR}/serde_test" - cd "${TRAVIS_BUILD_DIR}/serde_test"
- cargo build - cargo build
- rust: 1.15.0 - rust: 1.19.0
script:
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
- cargo build
- rust: 1.20.0 - rust: 1.20.0
- rust: 1.21.0 - rust: 1.21.0
- rust: 1.25.0 - rust: 1.25.0
- rust: 1.26.0 - rust: 1.26.0
# Work around failing to parse manifest because editions are unstable.
- rust: 1.27.0
before_script: sed -i /test_suite/d Cargo.toml
- rust: 1.28.0
before_script: sed -i /test_suite/d Cargo.toml
- rust: 1.31.0
script:
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
- cargo build
- rust: 1.34.0
- rust: 1.36.0
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build --no-default-features --features alloc
- rust: nightly - rust: nightly
name: Clippy name: Clippy
script: script:
+14 -12
View File
@@ -1,11 +1,13 @@
# Serde &emsp; [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc] # Serde &emsp; [![Build Status]][travis] [![Latest Version]][crates.io] [![serde: rustc 1.13+]][Rust 1.13] [![serde_derive: rustc 1.31+]][Rust 1.31]
[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master [Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master
[travis]: https://travis-ci.org/serde-rs/serde [travis]: https://travis-ci.org/serde-rs/serde
[Latest Version]: https://img.shields.io/crates/v/serde.svg [Latest Version]: https://img.shields.io/crates/v/serde.svg
[crates.io]: https://crates.io/crates/serde [crates.io]: https://crates.io/crates/serde
[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg [serde: rustc 1.13+]: https://img.shields.io/badge/serde-rustc_1.13+-lightgray.svg
[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html [serde_derive: rustc 1.31+]: https://img.shields.io/badge/serde_derive-rustc_1.31+-lightgray.svg
[Rust 1.13]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
@@ -81,19 +83,19 @@ good response, we are happy to respond to [GitHub issues][issues] as well.
[irc]: https://wiki.mozilla.org/IRC [irc]: https://wiki.mozilla.org/IRC
[issues]: https://github.com/serde-rs/serde/issues/new/choose [issues]: https://github.com/serde-rs/serde/issues/new/choose
## License <br>
Serde is licensed under either of #### License
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <sup>
http://www.apache.org/licenses/LICENSE-2.0) Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
* MIT license ([LICENSE-MIT](LICENSE-MIT) or 2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
http://opensource.org/licenses/MIT) </sup>
at your option. <br>
### Contribution
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions. dual licensed as above, without any additional terms or conditions.
</sub>
+1 -3
View File
@@ -35,7 +35,5 @@ for:
- cargo build --no-default-features --features alloc - cargo build --no-default-features --features alloc
- cargo build --no-default-features --features rc,alloc - cargo build --no-default-features --features rc,alloc
- cargo test --features derive,rc,unstable - cargo test --features derive,rc,unstable
- cd %APPVEYOR_BUILD_FOLDER%\test_suite\deps
- cargo build
- cd %APPVEYOR_BUILD_FOLDER%\test_suite - cd %APPVEYOR_BUILD_FOLDER%\test_suite
- cargo test --features compiletest,unstable - cargo test --features unstable
+4 -8
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.90" # remember to update html_root_url version = "1.0.103" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT OR Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
homepage = "https://serde.rs" homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
@@ -18,7 +18,7 @@ travis-ci = { repository = "serde-rs/serde" }
appveyor = { repository = "serde-rs/serde" } appveyor = { repository = "serde-rs/serde" }
[dependencies] [dependencies]
serde_derive = { version = "1.0", optional = true, path = "../serde_derive" } serde_derive = { version = "=1.0.103", optional = true, path = "../serde_derive" }
[dev-dependencies] [dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
@@ -48,11 +48,7 @@ unstable = []
# Provide impls for types in the Rust core allocation and collections library # Provide impls for types in the Rust core allocation and collections library
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may # including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
# be enabled without depending on all of std. # be enabled without depending on all of std.
# alloc = []
# Requires a dependency on the unstable core allocation library:
#
# https://doc.rust-lang.org/alloc/
alloc = ["unstable"]
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types # Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
# does not preserve identity and may result in multiple copies of the same data. # does not preserve identity and may result in multiple copies of the same data.
+28 -1
View File
@@ -29,10 +29,12 @@ fn main() {
println!("cargo:rustc-cfg=core_reverse"); println!("cargo:rustc-cfg=core_reverse");
} }
// CString::into_boxed_c_str stabilized in Rust 1.20: // CString::into_boxed_c_str and PathBuf::into_boxed_path stabilized in Rust 1.20:
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str // https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
// https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.into_boxed_path
if minor >= 20 { if minor >= 20 {
println!("cargo:rustc-cfg=de_boxed_c_str"); println!("cargo:rustc-cfg=de_boxed_c_str");
println!("cargo:rustc-cfg=de_boxed_path");
} }
// From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21: // From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
@@ -68,6 +70,31 @@ fn main() {
if minor >= 28 { if minor >= 28 {
println!("cargo:rustc-cfg=num_nonzero"); println!("cargo:rustc-cfg=num_nonzero");
} }
// TryFrom, Atomic types, and non-zero signed integers 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");
// Whitelist of archs that support std::sync::atomic module. Ideally we
// would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
// Instead this is based on rustc's src/librustc_target/spec/*.rs.
let has_atomic64 = target.starts_with("x86_64")
|| target.starts_with("i686")
|| target.starts_with("aarch64")
|| target.starts_with("powerpc64")
|| target.starts_with("sparc64")
|| target.starts_with("mips64el");
let has_atomic32 = has_atomic64 || emscripten;
if has_atomic64 {
println!("cargo:rustc-cfg=std_atomic64");
}
if has_atomic32 {
println!("cargo:rustc-cfg=std_atomic");
}
}
} }
fn rustc_minor_version() -> Option<u32> { fn rustc_minor_version() -> Option<u32> {
+10 -1
View File
@@ -1,6 +1,8 @@
use lib::*; use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; use de::{
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
};
/// An efficient way of discarding data from a deserializer. /// An efficient way of discarding data from a deserializer.
/// ///
@@ -205,6 +207,13 @@ impl<'de> Visitor<'de> for IgnoredAny {
let _ = bytes; let _ = bytes;
Ok(IgnoredAny) Ok(IgnoredAny)
} }
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
data.variant::<IgnoredAny>()?.1.newtype_variant()
}
} }
impl<'de> Deserialize<'de> for IgnoredAny { impl<'de> Deserialize<'de> for IgnoredAny {
+104 -42
View File
@@ -790,7 +790,8 @@ seq_impl!(
BinaryHeap::clear, BinaryHeap::clear,
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::reserve, BinaryHeap::reserve,
BinaryHeap::push); BinaryHeap::push
);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
@@ -799,7 +800,8 @@ seq_impl!(
BTreeSet::clear, BTreeSet::clear,
BTreeSet::new(), BTreeSet::new(),
nop_reserve, nop_reserve,
BTreeSet::insert); BTreeSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
@@ -965,7 +967,7 @@ impl<'de, T> Deserialize<'de> for [T; 0] {
} }
macro_rules! array_impls { macro_rules! array_impls {
($($len:expr => ($($n:tt $name:ident)+))+) => { ($($len:expr => ($($n:tt)+))+) => {
$( $(
impl<'de, T> Visitor<'de> for ArrayVisitor<[T; $len]> impl<'de, T> Visitor<'de> for ArrayVisitor<[T; $len]>
where where
@@ -982,14 +984,12 @@ macro_rules! array_impls {
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
$( Ok([$(
let $name = match try!(seq.next_element()) { match try!(seq.next_element()) {
Some(val) => val, Some(val) => val,
None => return Err(Error::invalid_length($n, &self)), None => return Err(Error::invalid_length($n, &self)),
}; }
)+ ),+])
Ok([$($name),+])
} }
} }
@@ -1045,38 +1045,38 @@ macro_rules! array_impls {
} }
array_impls! { array_impls! {
1 => (0 a) 1 => (0)
2 => (0 a 1 b) 2 => (0 1)
3 => (0 a 1 b 2 c) 3 => (0 1 2)
4 => (0 a 1 b 2 c 3 d) 4 => (0 1 2 3)
5 => (0 a 1 b 2 c 3 d 4 e) 5 => (0 1 2 3 4)
6 => (0 a 1 b 2 c 3 d 4 e 5 f) 6 => (0 1 2 3 4 5)
7 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g) 7 => (0 1 2 3 4 5 6)
8 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h) 8 => (0 1 2 3 4 5 6 7)
9 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i) 9 => (0 1 2 3 4 5 6 7 8)
10 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j) 10 => (0 1 2 3 4 5 6 7 8 9)
11 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k) 11 => (0 1 2 3 4 5 6 7 8 9 10)
12 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l) 12 => (0 1 2 3 4 5 6 7 8 9 10 11)
13 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m) 13 => (0 1 2 3 4 5 6 7 8 9 10 11 12)
14 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n) 14 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13)
15 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o) 15 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
16 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p) 16 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
17 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q) 17 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
18 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r) 18 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17)
19 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s) 19 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18)
20 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t) 20 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
21 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u) 21 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
22 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v) 22 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21)
23 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w) 23 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22)
24 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x) 24 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23)
25 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y) 25 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
26 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z) 26 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25)
27 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa) 27 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26)
28 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab) 28 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27)
29 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac) 29 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28)
30 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad) 30 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29)
31 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae) 31 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30)
32 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae 31 af) 32 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1580,6 +1580,24 @@ impl<'de> Visitor<'de> for PathBufVisitor {
{ {
Ok(From::from(v)) Ok(From::from(v))
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
str::from_utf8(v)
.map(From::from)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: Error,
{
String::from_utf8(v)
.map(From::from)
.map_err(|e| Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self))
}
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
@@ -1592,6 +1610,9 @@ impl<'de> Deserialize<'de> for PathBuf {
} }
} }
#[cfg(all(feature = "std", de_boxed_path))]
forwarded_impl!((), Box<Path>, PathBuf::into_boxed_path);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// If this were outside of the serde crate, it would just use: // If this were outside of the serde crate, it would just use:
@@ -2404,7 +2425,6 @@ macro_rules! nonzero_integers {
} }
nonzero_integers! { nonzero_integers! {
// Not including signed NonZeroI* since they might be removed
NonZeroU8, NonZeroU8,
NonZeroU16, NonZeroU16,
NonZeroU32, NonZeroU32,
@@ -2412,12 +2432,26 @@ nonzero_integers! {
NonZeroUsize, NonZeroUsize,
} }
#[cfg(num_nonzero_signed)]
nonzero_integers! {
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroIsize,
}
// Currently 128-bit integers do not work on Emscripten targets so we need an // Currently 128-bit integers do not work on Emscripten targets so we need an
// additional `#[cfg]` // additional `#[cfg]`
serde_if_integer128! { serde_if_integer128! {
nonzero_integers! { nonzero_integers! {
NonZeroU128, NonZeroU128,
} }
#[cfg(num_nonzero_signed)]
nonzero_integers! {
NonZeroI128,
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -2545,3 +2579,31 @@ where
Deserialize::deserialize(deserializer).map(Wrapping) Deserialize::deserialize(deserializer).map(Wrapping)
} }
} }
#[cfg(all(feature = "std", std_atomic))]
macro_rules! atomic_impl {
($($ty:ident)*) => {
$(
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Self::new)
}
}
)*
};
}
#[cfg(all(feature = "std", std_atomic))]
atomic_impl! {
AtomicBool
AtomicI8 AtomicI16 AtomicI32 AtomicIsize
AtomicU8 AtomicU16 AtomicU32 AtomicUsize
}
#[cfg(all(feature = "std", std_atomic64))]
atomic_impl! {
AtomicI64 AtomicU64
}
+9 -2
View File
@@ -125,6 +125,13 @@ mod utf8;
pub use self::ignored_any::IgnoredAny; pub use self::ignored_any::IgnoredAny;
#[cfg(feature = "std")]
#[doc(no_inline)]
pub use std::error::Error as StdError;
#[cfg(not(feature = "std"))]
#[doc(no_inline)]
pub use std_error::Error as StdError;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
macro_rules! declare_error_trait { macro_rules! declare_error_trait {
@@ -288,7 +295,7 @@ macro_rules! declare_error_trait {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
declare_error_trait!(Error: Sized + error::Error); declare_error_trait!(Error: Sized + StdError);
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
declare_error_trait!(Error: Sized + Debug + Display); declare_error_trait!(Error: Sized + Debug + Display);
@@ -787,7 +794,7 @@ where
/// ///
/// The role of this trait is to define the deserialization half of the [Serde /// The role of this trait is to define the deserialization half of the [Serde
/// data model], which is a way to categorize every Rust data type into one of /// data model], which is a way to categorize every Rust data type into one of
/// 29 possible types. Each method of the `Serializer` trait corresponds to one /// 29 possible types. Each method of the `Deserializer` trait corresponds to one
/// of the types of the data model. /// of the types of the data model.
/// ///
/// Implementations of `Deserialize` map themselves into this data model by /// Implementations of `Deserialize` map themselves into this data model by
+118 -2
View File
@@ -1287,10 +1287,40 @@ where
visitor.visit_map(self.map) visitor.visit_map(self.map)
} }
fn deserialize_enum<V>(
self,
_name: &str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_enum(self)
}
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any tuple_struct map struct identifier ignored_any
}
}
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
where
A: de::MapAccess<'de>,
{
type Error = A::Error;
type Variant = private::MapAsEnum<A>;
fn variant_seed<T>(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.map.next_key_seed(seed)? {
Some(key) => Ok((key, private::map_as_enum(self.map))),
None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")),
}
} }
} }
@@ -1299,7 +1329,7 @@ where
mod private { mod private {
use lib::*; use lib::*;
use de::{self, Unexpected}; use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UnitOnly<E> { pub struct UnitOnly<E> {
@@ -1360,6 +1390,92 @@ mod private {
} }
} }
#[derive(Clone, Debug)]
pub struct MapAsEnum<A> {
map: A,
}
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
MapAsEnum { map: map }
}
impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
where
A: MapAccess<'de>,
{
type Error = A::Error;
fn unit_variant(mut self) -> Result<(), Self::Error> {
self.map.next_value()
}
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
self.map.next_value_seed(seed)
}
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.map.next_value_seed(SeedTupleVariant {
len: len,
visitor: visitor,
})
}
fn struct_variant<V>(
mut self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.map
.next_value_seed(SeedStructVariant { visitor: visitor })
}
}
struct SeedTupleVariant<V> {
len: usize,
visitor: V,
}
impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant<V>
where
V: Visitor<'de>,
{
type Value = V::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple(self.len, self.visitor)
}
}
struct SeedStructVariant<V> {
visitor: V,
}
impl<'de, V> DeserializeSeed<'de> for SeedStructVariant<V>
where
V: Visitor<'de>,
{
type Value = V::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(self.visitor)
}
}
/// Avoid having to restate the generic types on `MapDeserializer`. The /// Avoid having to restate the generic types on `MapDeserializer`. The
/// `Iterator::Item` contains enough information to figure out K and V. /// `Iterator::Item` contains enough information to figure out K and V.
pub trait Pair { pub trait Pair {
+4 -1
View File
@@ -9,7 +9,10 @@ pub use lib::result::Result::{self, Err, Ok};
pub use self::string::from_utf8_lossy; pub use self::string::from_utf8_lossy;
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
pub use lib::Vec; pub use lib::{ToString, Vec};
#[cfg(core_try_from)]
pub use lib::convert::TryFrom;
mod string { mod string {
use lib::*; use lib::*;
+6 -6
View File
@@ -1,13 +1,13 @@
/// Conditional compilation depending on whether Serde is built with support for /// Conditional compilation depending on whether Serde is built with support for
/// 128-bit integers. /// 128-bit integers.
/// ///
/// Data formats that wish to support Rust compiler versions older than 1.26 may /// Data formats that wish to support Rust compiler versions older than 1.26
/// place the i128 / u128 methods of their Serializer and Deserializer behind /// (or targets that lack 128-bit integers) may place the i128 / u128 methods
/// this macro. /// of their Serializer and Deserializer behind this macro.
/// ///
/// Data formats that require a minimum Rust compiler version of at least 1.26 /// Data formats that require a minimum Rust compiler version of at least 1.26,
/// do not need to bother with this macro and may assume support for 128-bit /// or do not target platforms that lack 128-bit integers, do not need to
/// integers. /// bother with this macro and may assume support for 128-bit integers.
/// ///
/// ```edition2018 /// ```edition2018
/// # use serde::private::ser::Error; /// # use serde::private::ser::Error;
+24 -8
View File
@@ -46,8 +46,8 @@
//! - [BSON], the data storage and network transfer format used by MongoDB. //! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema //! - [Avro], a binary format used within Apache Hadoop, with support for schema
//! definition. //! definition.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [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], the x-www-form-urlencoded format. //! - [URL], the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs. //! - [Envy], a way to deserialize environment variables into Rust structs.
//! *(deserialization only)* //! *(deserialization only)*
@@ -64,8 +64,8 @@
//! [RON]: https://github.com/ron-rs/ron //! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs //! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs //! [Avro]: https://github.com/flavray/avro-rs
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [JSON5]: https://github.com/callum-oakley/json5-rs //! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [URL]: https://github.com/nox/serde_urlencoded //! [URL]: https://github.com/nox/serde_urlencoded
//! [Envy]: https://github.com/softprops/envy //! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store //! [Envy Store]: https://github.com/softprops/envy-store
@@ -75,15 +75,15 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.90")] #![doc(html_root_url = "https://docs.rs/serde/1.0.103")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue: // discussion of these features please refer to this issue:
// //
// https://github.com/serde-rs/serde/issues/812 // https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(specialization, never_type))] #![cfg_attr(feature = "unstable", feature(specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))] #![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy and clippy_pedantic lints // Ignored clippy and clippy_pedantic lints
@@ -91,13 +91,13 @@
feature = "cargo-clippy", feature = "cargo-clippy",
allow( allow(
// not available in our oldest supported compiler // not available in our oldest supported compiler
const_static_lifetime, checked_conversions,
empty_enum, empty_enum,
redundant_field_names, redundant_field_names,
redundant_static_lifetimes,
// integer and float ser/de requires these sorts of casts // integer and float ser/de requires these sorts of casts
cast_possible_truncation, cast_possible_truncation,
cast_possible_wrap, cast_possible_wrap,
cast_precision_loss,
cast_sign_loss, cast_sign_loss,
// things are often more readable this way // things are often more readable this way
cast_lossless, cast_lossless,
@@ -109,8 +109,13 @@
// not practical // not practical
needless_pass_by_value, needless_pass_by_value,
similar_names, similar_names,
too_many_lines,
// preference // preference
doc_markdown, doc_markdown,
// false positive
needless_doctest_main,
// noisy
must_use_candidate,
) )
)] )]
// Rustc lints. // Rustc lints.
@@ -155,7 +160,7 @@ mod lib {
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString}; pub use alloc::string::{String, ToString};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::string::String; pub use std::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec; pub use alloc::vec::Vec;
@@ -214,6 +219,14 @@ mod lib {
#[cfg(range_inclusive)] #[cfg(range_inclusive)]
pub use self::core::ops::RangeInclusive; pub use self::core::ops::RangeInclusive;
#[cfg(all(feature = "std", std_atomic))]
pub use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize, Ordering,
};
#[cfg(all(feature = "std", std_atomic64))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(any(core_duration, feature = "std"))] #[cfg(any(core_duration, feature = "std"))]
pub use self::core::time::Duration; pub use self::core::time::Duration;
} }
@@ -242,6 +255,9 @@ pub mod export;
#[doc(hidden)] #[doc(hidden)]
pub mod private; pub mod private;
#[cfg(not(feature = "std"))]
mod std_error;
// Re-export #[derive(Serialize, Deserialize)]. // Re-export #[derive(Serialize, Deserialize)].
// //
// The reason re-exporting is not enabled by default is that disabling it would // The reason re-exporting is not enabled by default is that disabling it would
+9
View File
@@ -1420,6 +1420,7 @@ mod content {
Content::ByteBuf(v) => visitor.visit_byte_buf(v), Content::ByteBuf(v) => visitor.visit_byte_buf(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v), Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::U8(v) => visitor.visit_u8(v), Content::U8(v) => visitor.visit_u8(v),
Content::U64(v) => visitor.visit_u64(v),
_ => Err(self.invalid_type(&visitor)), _ => Err(self.invalid_type(&visitor)),
} }
} }
@@ -2123,6 +2124,7 @@ mod content {
Content::ByteBuf(ref v) => visitor.visit_bytes(v), Content::ByteBuf(ref v) => visitor.visit_bytes(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v), Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::U8(v) => visitor.visit_u8(v), Content::U8(v) => visitor.visit_u8(v),
Content::U64(v) => visitor.visit_u64(v),
_ => Err(self.invalid_type(&visitor)), _ => Err(self.invalid_type(&visitor)),
} }
} }
@@ -2508,6 +2510,13 @@ mod content {
{ {
Ok(()) Ok(())
} }
fn visit_none<E>(self) -> Result<(), E>
where
E: de::Error,
{
Ok(())
}
} }
} }
+22 -22
View File
@@ -1032,7 +1032,7 @@ impl<'a, M> FlatMapSerializer<'a, M>
where where
M: SerializeMap + 'a, M: SerializeMap + 'a,
{ {
fn bad_type(self, what: Unsupported) -> M::Error { fn bad_type(what: Unsupported) -> M::Error {
ser::Error::custom(format_args!( ser::Error::custom(format_args!(
"can only flatten structs and maps (got {})", "can only flatten structs and maps (got {})",
what what
@@ -1057,59 +1057,59 @@ where
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>; type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Boolean)) Err(Self::bad_type(Unsupported::Boolean))
} }
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> { fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> { fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> { fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> { fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> { fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> { fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> { fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> { fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer)) Err(Self::bad_type(Unsupported::Integer))
} }
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> { fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float)) Err(Self::bad_type(Unsupported::Float))
} }
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> { fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float)) Err(Self::bad_type(Unsupported::Float))
} }
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> { fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Char)) Err(Self::bad_type(Unsupported::Char))
} }
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> { fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::String)) Err(Self::bad_type(Unsupported::String))
} }
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> { fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::ByteArray)) Err(Self::bad_type(Unsupported::ByteArray))
} }
fn serialize_none(self) -> Result<Self::Ok, Self::Error> { fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
@@ -1124,11 +1124,11 @@ where
} }
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Unit)) Err(Self::bad_type(Unsupported::Unit))
} }
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::UnitStruct)) Err(Self::bad_type(Unsupported::UnitStruct))
} }
fn serialize_unit_variant( fn serialize_unit_variant(
@@ -1137,7 +1137,7 @@ where
_: u32, _: u32,
_: &'static str, _: &'static str,
) -> Result<Self::Ok, Self::Error> { ) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Enum)) Err(Self::bad_type(Unsupported::Enum))
} }
fn serialize_newtype_struct<T: ?Sized>( fn serialize_newtype_struct<T: ?Sized>(
@@ -1166,11 +1166,11 @@ where
} }
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(self.bad_type(Unsupported::Sequence)) Err(Self::bad_type(Unsupported::Sequence))
} }
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> { fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(self.bad_type(Unsupported::Tuple)) Err(Self::bad_type(Unsupported::Tuple))
} }
fn serialize_tuple_struct( fn serialize_tuple_struct(
@@ -1178,7 +1178,7 @@ where
_: &'static str, _: &'static str,
_: usize, _: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> { ) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(self.bad_type(Unsupported::TupleStruct)) Err(Self::bad_type(Unsupported::TupleStruct))
} }
fn serialize_tuple_variant( fn serialize_tuple_variant(
@@ -1188,7 +1188,7 @@ where
_: &'static str, _: &'static str,
_: usize, _: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> { ) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(self.bad_type(Unsupported::Enum)) Err(Self::bad_type(Unsupported::Enum))
} }
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+45 -1
View File
@@ -481,7 +481,6 @@ macro_rules! nonzero_integers {
} }
nonzero_integers! { nonzero_integers! {
// Not including signed NonZeroI* since they might be removed
NonZeroU8, NonZeroU8,
NonZeroU16, NonZeroU16,
NonZeroU32, NonZeroU32,
@@ -489,12 +488,26 @@ nonzero_integers! {
NonZeroUsize, NonZeroUsize,
} }
#[cfg(num_nonzero_signed)]
nonzero_integers! {
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroIsize,
}
// Currently 128-bit integers do not work on Emscripten targets so we need an // Currently 128-bit integers do not work on Emscripten targets so we need an
// additional `#[cfg]` // additional `#[cfg]`
serde_if_integer128! { serde_if_integer128! {
nonzero_integers! { nonzero_integers! {
NonZeroU128, NonZeroU128,
} }
#[cfg(num_nonzero_signed)]
nonzero_integers! {
NonZeroI128,
}
} }
impl<T> Serialize for Cell<T> impl<T> Serialize for Cell<T>
@@ -620,6 +633,7 @@ impl Serialize for SystemTime {
#[cfg(feature = "std")] #[cfg(feature = "std")]
macro_rules! serialize_display_bounded_length { macro_rules! serialize_display_bounded_length {
($value:expr, $max:expr, $serializer:expr) => {{ ($value:expr, $max:expr, $serializer:expr) => {{
#[allow(deprecated)]
let mut buffer: [u8; $max] = unsafe { mem::uninitialized() }; let mut buffer: [u8; $max] = unsafe { mem::uninitialized() };
let remaining_len = { let remaining_len = {
let mut remaining = &mut buffer[..]; let mut remaining = &mut buffer[..];
@@ -838,3 +852,33 @@ where
self.0.serialize(serializer) self.0.serialize(serializer)
} }
} }
////////////////////////////////////////////////////////////////////////////////
#[cfg(all(feature = "std", std_atomic))]
macro_rules! atomic_impl {
($($ty:ident)*) => {
$(
impl Serialize for $ty {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.load(Ordering::SeqCst).serialize(serializer)
}
}
)*
}
}
#[cfg(all(feature = "std", std_atomic))]
atomic_impl! {
AtomicBool
AtomicI8 AtomicI16 AtomicI32 AtomicIsize
AtomicU8 AtomicU16 AtomicU32 AtomicUsize
}
#[cfg(all(feature = "std", std_atomic64))]
atomic_impl! {
AtomicI64 AtomicU64
}
+8 -1
View File
@@ -114,6 +114,13 @@ mod impossible;
pub use self::impossible::Impossible; pub use self::impossible::Impossible;
#[cfg(feature = "std")]
#[doc(no_inline)]
pub use std::error::Error as StdError;
#[cfg(not(feature = "std"))]
#[doc(no_inline)]
pub use std_error::Error as StdError;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
macro_rules! declare_error_trait { macro_rules! declare_error_trait {
@@ -172,7 +179,7 @@ macro_rules! declare_error_trait {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
declare_error_trait!(Error: Sized + error::Error); declare_error_trait!(Error: Sized + StdError);
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
declare_error_trait!(Error: Sized + Debug + Display); declare_error_trait!(Error: Sized + Debug + Display);
+48
View File
@@ -0,0 +1,48 @@
use lib::{Debug, Display};
/// Either a re-export of std::error::Error or a new identical trait, depending
/// on whether Serde's "std" feature is enabled.
///
/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require
/// [`std::error::Error`] as a supertrait, but only when Serde is built with
/// "std" enabled. Data formats that don't care about no\_std support should
/// generally provide their error types with a `std::error::Error` impl
/// directly:
///
/// ```edition2018
/// #[derive(Debug)]
/// struct MySerError {...}
///
/// impl serde::ser::Error for MySerError {...}
///
/// impl std::fmt::Display for MySerError {...}
///
/// // We don't support no_std!
/// impl std::error::Error for MySerError {}
/// ```
///
/// Data formats that *do* support no\_std may either have a "std" feature of
/// their own:
///
/// ```toml
/// [features]
/// std = ["serde/std"]
/// ```
///
/// ```edition2018
/// #[cfg(feature = "std")]
/// impl std::error::Error for MySerError {}
/// ```
///
/// ... or else provide the std Error impl unconditionally via Serde's
/// re-export:
///
/// ```edition2018
/// impl serde::ser::StdError for MySerError {}
/// ```
pub trait Error: Debug + Display {
/// The underlying cause of this error, if any.
fn source(&self) -> Option<&(Error + 'static)> {
None
}
}
+5 -5
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.90" # remember to update html_root_url version = "1.0.103" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT OR Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
homepage = "https://serde.rs" homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
@@ -24,9 +24,9 @@ name = "serde_derive"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "0.4" proc-macro2 = "1.0"
quote = "0.6.3" quote = "1.0"
syn = { version = "0.15.22", features = ["visit"] } syn = { version = "1.0", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+16 -16
View File
@@ -17,8 +17,8 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
params: generics params: generics
.params .params
.iter() .iter()
.map(|param| match *param { .map(|param| match param {
syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam { syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
eq_token: None, eq_token: None,
default: None, default: None,
..param.clone() ..param.clone()
@@ -63,8 +63,8 @@ pub fn with_where_predicates_from_variants(
generics: &syn::Generics, generics: &syn::Generics,
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>, from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics { ) -> syn::Generics {
let variants = match cont.data { let variants = match &cont.data {
Data::Enum(ref variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => {
return generics.clone(); return generics.clone();
} }
@@ -114,8 +114,8 @@ pub fn with_bound(
} }
impl<'ast> Visit<'ast> for FindTyParams<'ast> { impl<'ast> Visit<'ast> for FindTyParams<'ast> {
fn visit_field(&mut self, field: &'ast syn::Field) { fn visit_field(&mut self, field: &'ast syn::Field) {
if let syn::Type::Path(ref ty) = field.ty { if let syn::Type::Path(ty) = &field.ty {
if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() { if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
if self.all_type_params.contains(&t.ident) { if self.all_type_params.contains(&t.ident) {
self.associated_type_usage.push(ty); self.associated_type_usage.push(ty);
} }
@@ -126,7 +126,7 @@ pub fn with_bound(
fn visit_path(&mut self, path: &'ast syn::Path) { fn visit_path(&mut self, path: &'ast syn::Path) {
if let Some(seg) = path.segments.last() { if let Some(seg) = path.segments.last() {
if seg.into_value().ident == "PhantomData" { if seg.ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements // Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it. // Serialize and Deserialize whether or not T implements it.
return; return;
@@ -160,8 +160,8 @@ pub fn with_bound(
relevant_type_params: HashSet::new(), relevant_type_params: HashSet::new(),
associated_type_usage: Vec::new(), associated_type_usage: Vec::new(),
}; };
match cont.data { match &cont.data {
Data::Enum(ref variants) => { Data::Enum(variants) => {
for variant in variants.iter() { for variant in variants.iter() {
let relevant_fields = variant let relevant_fields = variant
.fields .fields
@@ -172,7 +172,7 @@ pub fn with_bound(
} }
} }
} }
Data::Struct(_, ref fields) => { Data::Struct(_, fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) { for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visitor.visit_field(field.original); visitor.visit_field(field.original);
} }
@@ -255,11 +255,11 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
let params = Some(syn::GenericParam::Lifetime(def)) let params = Some(syn::GenericParam::Lifetime(def))
.into_iter() .into_iter()
.chain(generics.params.iter().cloned().map(|mut param| { .chain(generics.params.iter().cloned().map(|mut param| {
match param { match &mut param {
syn::GenericParam::Lifetime(ref mut param) => { syn::GenericParam::Lifetime(param) => {
param.bounds.push(bound.clone()); param.bounds.push(bound.clone());
} }
syn::GenericParam::Type(ref mut param) => { syn::GenericParam::Type(param) => {
param param
.bounds .bounds
.push(syn::TypeParamBound::Lifetime(bound.clone())); .push(syn::TypeParamBound::Lifetime(bound.clone()));
@@ -291,14 +291,14 @@ fn type_of_item(cont: &Container) -> syn::Type {
.generics .generics
.params .params
.iter() .iter()
.map(|param| match *param { .map(|param| match param {
syn::GenericParam::Type(ref param) => { syn::GenericParam::Type(param) => {
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
qself: None, qself: None,
path: param.ident.clone().into(), path: param.ident.clone().into(),
})) }))
} }
syn::GenericParam::Lifetime(ref param) => { syn::GenericParam::Lifetime(param) => {
syn::GenericArgument::Lifetime(param.lifetime.clone()) syn::GenericArgument::Lifetime(param.lifetime.clone())
} }
syn::GenericParam::Const(_) => { syn::GenericParam::Const(_) => {
+111 -76
View File
@@ -20,7 +20,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream
None => return Err(ctxt.check().unwrap_err()), None => return Err(ctxt.check().unwrap_err()),
}; };
precondition(&ctxt, &cont); precondition(&ctxt, &cont);
try!(ctxt.check()); ctxt.check()?;
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
@@ -75,7 +75,7 @@ fn precondition(cx: &Ctxt, cont: &Container) {
} }
fn precondition_sized(cx: &Ctxt, cont: &Container) { fn precondition_sized(cx: &Ctxt, cont: &Container) {
if let Data::Struct(_, ref fields) = cont.data { if let Data::Struct(_, fields) = &cont.data {
if let Some(last) = fields.last() { if let Some(last) = fields.last() {
if let syn::Type::Slice(_) = *last.ty { if let syn::Type::Slice(_) = *last.ty {
cx.error_spanned_by( cx.error_spanned_by(
@@ -145,7 +145,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Deserializer methods. /// various Deserializer methods.
fn type_name(&self) -> String { fn type_name(&self) -> String {
self.this.segments.last().unwrap().value().ident.to_string() self.this.segments.last().unwrap().ident.to_string()
} }
} }
@@ -229,8 +229,8 @@ impl BorrowedLifetimes {
} }
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> { fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
match *self { match self {
BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef { BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()), lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None, colon_token: None,
@@ -269,22 +269,22 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
deserialize_transparent(cont, params) deserialize_transparent(cont, params)
} else if let Some(type_from) = cont.attrs.type_from() { } else if let Some(type_from) = cont.attrs.type_from() {
deserialize_from(type_from) deserialize_from(type_from)
} else if let Some(type_try_from) = cont.attrs.type_try_from() {
deserialize_try_from(type_try_from)
} else if let attr::Identifier::No = cont.attrs.identifier() { } else if let attr::Identifier::No = cont.attrs.identifier() {
match cont.data { match &cont.data {
Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, fields) => {
deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No)
} }
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
deserialize_tuple(None, params, fields, &cont.attrs, None) deserialize_tuple(None, params, fields, &cont.attrs, None)
} }
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
} }
} else { } else {
match cont.data { match &cont.data {
Data::Enum(ref variants) => { Data::Enum(variants) => deserialize_custom_identifier(params, variants, &cont.attrs),
deserialize_custom_identifier(params, variants, &cont.attrs)
}
Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"),
} }
} }
@@ -298,6 +298,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
if cont.attrs.transparent() if cont.attrs.transparent()
|| cont.attrs.type_from().is_some() || cont.attrs.type_from().is_some()
|| cont.attrs.type_try_from().is_some()
|| cont.attrs.identifier().is_some() || cont.attrs.identifier().is_some()
|| cont || cont
.data .data
@@ -307,8 +308,8 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
return None; return None;
} }
let code = match cont.data { let code = match &cont.data {
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, fields) => {
if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None) if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None)
{ {
code code
@@ -316,7 +317,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
return None; return None;
} }
} }
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None) deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
} }
Data::Enum(_) | Data::Struct(Style::Unit, _) => { Data::Enum(_) | Data::Struct(Style::Unit, _) => {
@@ -345,8 +346,8 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<
} }
fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let fields = match cont.data { let fields = match &cont.data {
Data::Struct(_, ref fields) => fields, Data::Struct(_, fields) => fields,
Data::Enum(_) => unreachable!(), Data::Enum(_) => unreachable!(),
}; };
@@ -366,9 +367,9 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
if field as *const Field == transparent_field as *const Field { if field as *const Field == transparent_field as *const Field {
quote!(#member: __transparent) quote!(#member: __transparent)
} else { } else {
let value = match *field.attrs.default() { let value = match field.attrs.default() {
attr::Default::Default => quote!(_serde::export::Default::default()), attr::Default::Default => quote!(_serde::export::Default::default()),
attr::Default::Path(ref path) => quote!(#path()), attr::Default::Path(path) => quote!(#path()),
attr::Default::None => quote!(_serde::export::PhantomData), attr::Default::None => quote!(_serde::export::PhantomData),
}; };
quote!(#member: #value) quote!(#member: #value)
@@ -390,6 +391,14 @@ fn deserialize_from(type_from: &syn::Type) -> Fragment {
} }
} }
fn deserialize_try_from(type_try_from: &syn::Type) -> Fragment {
quote_block! {
_serde::export::Result::and_then(
<#type_try_from as _serde::Deserialize>::deserialize(__deserializer),
|v| _serde::export::TryFrom::try_from(v).map_err(_serde::de::Error::custom))
}
}
fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment {
let this = &params.this; let this = &params.this;
let type_name = cattrs.name().deserialize_name(); let type_name = cattrs.name().deserialize_name();
@@ -445,7 +454,7 @@ fn deserialize_tuple(
let is_enum = variant_ident.is_some(); let is_enum = variant_ident.is_some();
let type_path = match variant_ident { let type_path = match variant_ident {
Some(ref variant_ident) => quote!(#construct::#variant_ident), Some(variant_ident) => quote!(#construct::#variant_ident),
None => construct, None => construct,
}; };
let expecting = match variant_ident { let expecting = match variant_ident {
@@ -653,9 +662,9 @@ fn deserialize_seq(
}) })
} }
}; };
let value_if_none = match *field.attrs.default() { let value_if_none = match field.attrs.default() {
attr::Default::Default => quote!(_serde::export::Default::default()), attr::Default::Default => quote!(_serde::export::Default::default()),
attr::Default::Path(ref path) => quote!(#path()), attr::Default::Path(path) => quote!(#path()),
attr::Default::None => quote!( attr::Default::None => quote!(
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
), ),
@@ -691,11 +700,11 @@ fn deserialize_seq(
}; };
} }
let let_default = match *cattrs.default() { let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!( attr::Default::Default => Some(quote!(
let __default: Self::Value = _serde::export::Default::default(); let __default: Self::Value = _serde::export::Default::default();
)), )),
attr::Default::Path(ref path) => Some(quote!( attr::Default::Path(path) => Some(quote!(
let __default: Self::Value = #path(); let __default: Self::Value = #path();
)), )),
attr::Default::None => { attr::Default::None => {
@@ -739,11 +748,11 @@ fn deserialize_seq_in_place(
self.place.#member = #default; self.place.#member = #default;
} }
} else { } else {
let value_if_none = match *field.attrs.default() { let value_if_none = match field.attrs.default() {
attr::Default::Default => quote!( attr::Default::Default => quote!(
self.place.#member = _serde::export::Default::default(); self.place.#member = _serde::export::Default::default();
), ),
attr::Default::Path(ref path) => quote!( attr::Default::Path(path) => quote!(
self.place.#member = #path(); self.place.#member = #path();
), ),
attr::Default::None => quote!( attr::Default::None => quote!(
@@ -782,11 +791,11 @@ fn deserialize_seq_in_place(
let this = &params.this; let this = &params.this;
let (_, ty_generics, _) = params.generics.split_for_impl(); let (_, ty_generics, _) = params.generics.split_for_impl();
let let_default = match *cattrs.default() { let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!( attr::Default::Default => Some(quote!(
let __default: #this #ty_generics = _serde::export::Default::default(); let __default: #this #ty_generics = _serde::export::Default::default();
)), )),
attr::Default::Path(ref path) => Some(quote!( attr::Default::Path(path) => Some(quote!(
let __default: #this #ty_generics = #path(); let __default: #this #ty_generics = #path();
)), )),
attr::Default::None => { attr::Default::None => {
@@ -896,7 +905,7 @@ fn deserialize_struct(
}; };
let type_path = match variant_ident { let type_path = match variant_ident {
Some(ref variant_ident) => quote!(#construct::#variant_ident), Some(variant_ident) => quote!(#construct::#variant_ident),
None => construct, None => construct,
}; };
let expecting = match variant_ident { let expecting = match variant_ident {
@@ -1133,15 +1142,14 @@ fn deserialize_enum(
variants: &[Variant], variants: &[Variant],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
match *cattrs.tag() { match cattrs.tag() {
attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs),
attr::TagType::Internal { ref tag } => { attr::TagType::Internal { tag } => {
deserialize_internally_tagged_enum(params, variants, cattrs, tag) deserialize_internally_tagged_enum(params, variants, cattrs, tag)
} }
attr::TagType::Adjacent { attr::TagType::Adjacent { tag, content } => {
ref tag, deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content)
ref content, }
} => deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content),
attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs), attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs),
} }
} }
@@ -1163,12 +1171,10 @@ fn prepare_enum_variant_enum(
}) })
.collect(); .collect();
let other_idx = variants let other_idx = variants.iter().position(|variant| variant.attrs.other());
.iter()
.position(|ref variant| variant.attrs.other());
let variants_stmt = { let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|&(ref name, _, _)| name); let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
quote! { quote! {
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
} }
@@ -1677,9 +1683,12 @@ fn deserialize_externally_tagged_variant(
_serde::export::Ok(#this::#variant_ident) _serde::export::Ok(#this::#variant_ident)
} }
} }
Style::Newtype => { Style::Newtype => deserialize_externally_tagged_newtype_variant(
deserialize_externally_tagged_newtype_variant(variant_ident, params, &variant.fields[0]) variant_ident,
} params,
&variant.fields[0],
cattrs,
),
Style::Tuple => { Style::Tuple => {
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None) deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
} }
@@ -1706,14 +1715,18 @@ fn deserialize_internally_tagged_variant(
let variant_ident = &variant.ident; let variant_ident = &variant.ident;
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
let this = &params.this; let this = &params.this;
let type_name = params.type_name(); let type_name = params.type_name();
let variant_name = variant.ident.to_string(); let variant_name = variant.ident.to_string();
let default = variant.fields.get(0).map(|field| {
let default = Expr(expr_is_missing(field, cattrs));
quote!((#default))
});
quote_block! { quote_block! {
try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))); try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name)));
_serde::export::Ok(#this::#variant_ident) _serde::export::Ok(#this::#variant_ident #default)
} }
} }
Style::Newtype => deserialize_untagged_newtype_variant( Style::Newtype => deserialize_untagged_newtype_variant(
@@ -1751,17 +1764,21 @@ fn deserialize_untagged_variant(
let variant_ident = &variant.ident; let variant_ident = &variant.ident;
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
let this = &params.this; let this = &params.this;
let type_name = params.type_name(); let type_name = params.type_name();
let variant_name = variant.ident.to_string(); let variant_name = variant.ident.to_string();
let default = variant.fields.get(0).map(|field| {
let default = Expr(expr_is_missing(field, cattrs));
quote!((#default))
});
quote_expr! { quote_expr! {
match _serde::Deserializer::deserialize_any( match _serde::Deserializer::deserialize_any(
#deserializer, #deserializer,
_serde::private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) _serde::private::de::UntaggedUnitVisitor::new(#type_name, #variant_name)
) { ) {
_serde::export::Ok(()) => _serde::export::Ok(#this::#variant_ident), _serde::export::Ok(()) => _serde::export::Ok(#this::#variant_ident #default),
_serde::export::Err(__err) => _serde::export::Err(__err), _serde::export::Err(__err) => _serde::export::Err(__err),
} }
} }
@@ -1794,8 +1811,19 @@ fn deserialize_externally_tagged_newtype_variant(
variant_ident: &syn::Ident, variant_ident: &syn::Ident,
params: &Parameters, params: &Parameters,
field: &Field, field: &Field,
cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
let this = &params.this; let this = &params.this;
if field.attrs.skip_deserializing() {
let this = &params.this;
let default = Expr(expr_is_missing(field, cattrs));
return quote_block! {
try!(_serde::de::VariantAccess::unit_variant(__variant));
_serde::export::Ok(#this::#variant_ident(#default))
};
}
match field.attrs.deserialize_with() { match field.attrs.deserialize_with() {
None => { None => {
let field_ty = field.ty; let field_ty = field.ty;
@@ -1850,7 +1878,7 @@ fn deserialize_generated_identifier(
other_idx: Option<usize>, other_idx: Option<usize>,
) -> Fragment { ) -> Fragment {
let this = quote!(__Field); let this = quote!(__Field);
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident, _)| ident).collect(); let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect();
let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() {
let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),); let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),);
@@ -1956,7 +1984,7 @@ fn deserialize_custom_identifier(
}) })
.collect(); .collect();
let names = names_idents.iter().map(|&(ref name, _, _)| name); let names = names_idents.iter().map(|(name, _, _)| name);
let names_const = if fallthrough.is_some() { let names_const = if fallthrough.is_some() {
None None
@@ -2013,26 +2041,26 @@ fn deserialize_identifier(
collect_other_fields: bool, collect_other_fields: bool,
) -> Fragment { ) -> Fragment {
let mut flat_fields = Vec::new(); let mut flat_fields = Vec::new();
for &(_, ref ident, ref aliases) in fields { 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 = flat_fields.iter().map(|&(ref name, _)| name); let field_strs = flat_fields.iter().map(|(name, _)| name);
let field_borrowed_strs = flat_fields.iter().map(|&(ref name, _)| name); let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name);
let field_bytes = flat_fields let field_bytes = flat_fields
.iter() .iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); .map(|(name, _)| Literal::byte_string(name.as_bytes()));
let field_borrowed_bytes = flat_fields let field_borrowed_bytes = flat_fields
.iter() .iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); .map(|(name, _)| Literal::byte_string(name.as_bytes()));
let constructors: &Vec<_> = &flat_fields let constructors: &Vec<_> = &flat_fields
.iter() .iter()
.map(|&(_, ref ident)| quote!(#this::#ident)) .map(|(_, ident)| quote!(#this::#ident))
.collect(); .collect();
let main_constructors: &Vec<_> = &fields let main_constructors: &Vec<_> = &fields
.iter() .iter()
.map(|&(_, ref ident, _)| quote!(#this::#ident)) .map(|(_, ident, _)| quote!(#this::#ident))
.collect(); .collect();
let expecting = if is_variant { let expecting = if is_variant {
@@ -2059,7 +2087,7 @@ fn deserialize_identifier(
) = if collect_other_fields { ) = if collect_other_fields {
( (
Some(quote! { Some(quote! {
let __value = _serde::private::de::Content::String(__value.to_string()); let __value = _serde::private::de::Content::String(_serde::export::ToString::to_string(__value));
}), }),
Some(quote! { Some(quote! {
let __value = _serde::private::de::Content::Str(__value); let __value = _serde::private::de::Content::Str(__value);
@@ -2294,7 +2322,7 @@ fn deserialize_struct_as_struct_visitor(
.collect(); .collect();
let fields_stmt = { let fields_stmt = {
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name); let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! { quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
} }
@@ -2350,7 +2378,7 @@ fn deserialize_map(
let let_values = fields_names let let_values = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| { .map(|(field, name)| {
let field_ty = field.ty; let field_ty = field.ty;
quote! { quote! {
let mut #name: _serde::export::Option<#field_ty> = _serde::export::None; let mut #name: _serde::export::Option<#field_ty> = _serde::export::None;
@@ -2373,7 +2401,7 @@ fn deserialize_map(
let value_arms = fields_names let value_arms = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| { .map(|(field, name)| {
let deser_name = field.attrs.name().deserialize_name(); let deser_name = field.attrs.name().deserialize_name();
let visit = match field.attrs.deserialize_with() { let visit = match field.attrs.deserialize_with() {
@@ -2449,7 +2477,7 @@ fn deserialize_map(
let extract_values = fields_names let extract_values = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| { .map(|(field, name)| {
let missing_expr = Match(expr_is_missing(field, cattrs)); let missing_expr = Match(expr_is_missing(field, cattrs));
quote! { quote! {
@@ -2463,7 +2491,7 @@ fn deserialize_map(
let extract_collected = fields_names let extract_collected = fields_names
.iter() .iter()
.filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing())
.map(|&(field, ref name)| { .map(|(field, name)| {
let field_ty = field.ty; let field_ty = field.ty;
let func = match field.attrs.deserialize_with() { let func = match field.attrs.deserialize_with() {
None => { None => {
@@ -2498,7 +2526,7 @@ fn deserialize_map(
None None
}; };
let result = fields_names.iter().map(|&(field, ref name)| { let result = fields_names.iter().map(|(field, name)| {
let member = &field.member; let member = &field.member;
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let value = Expr(expr_is_missing(field, cattrs)); let value = Expr(expr_is_missing(field, cattrs));
@@ -2508,11 +2536,11 @@ fn deserialize_map(
} }
}); });
let let_default = match *cattrs.default() { let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!( attr::Default::Default => Some(quote!(
let __default: Self::Value = _serde::export::Default::default(); let __default: Self::Value = _serde::export::Default::default();
)), )),
attr::Default::Path(ref path) => Some(quote!( attr::Default::Path(path) => Some(quote!(
let __default: Self::Value = #path(); let __default: Self::Value = #path();
)), )),
attr::Default::None => { attr::Default::None => {
@@ -2571,7 +2599,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
.collect(); .collect();
let fields_stmt = { let fields_stmt = {
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name); let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! { quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
} }
@@ -2604,7 +2632,7 @@ fn deserialize_map_in_place(
let let_flags = fields_names let let_flags = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing()) .filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|&(_, ref name)| { .map(|(_, name)| {
quote! { quote! {
let mut #name: bool = false; let mut #name: bool = false;
} }
@@ -2614,7 +2642,7 @@ fn deserialize_map_in_place(
let value_arms_from = fields_names let value_arms_from = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing()) .filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|&(field, ref name)| { .map(|(field, name)| {
let deser_name = field.attrs.name().deserialize_name(); let deser_name = field.attrs.name().deserialize_name();
let member = &field.member; let member = &field.member;
@@ -2681,7 +2709,7 @@ fn deserialize_map_in_place(
let check_flags = fields_names let check_flags = fields_names
.iter() .iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing()) .filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|&(field, ref name)| { .map(|(field, name)| {
let missing_expr = expr_is_missing(field, cattrs); let missing_expr = expr_is_missing(field, cattrs);
// If missing_expr unconditionally returns an error, don't try // If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place. // to assign its value to self.place.
@@ -2709,11 +2737,11 @@ fn deserialize_map_in_place(
let this = &params.this; let this = &params.this;
let (_, _, ty_generics, _) = split_with_de_lifetime(params); let (_, _, ty_generics, _) = split_with_de_lifetime(params);
let let_default = match *cattrs.default() { let let_default = match cattrs.default() {
attr::Default::Default => Some(quote!( attr::Default::Default => Some(quote!(
let __default: #this #ty_generics = _serde::export::Default::default(); let __default: #this #ty_generics = _serde::export::Default::default();
)), )),
attr::Default::Path(ref path) => Some(quote!( attr::Default::Path(path) => Some(quote!(
let __default: #this #ty_generics = #path(); let __default: #this #ty_generics = #path();
)), )),
attr::Default::None => { attr::Default::None => {
@@ -2832,13 +2860,13 @@ fn wrap_deserialize_variant_with(
} }
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
match *field.attrs.default() { match field.attrs.default() {
attr::Default::Default => { attr::Default::Default => {
let span = field.original.span(); let span = field.original.span();
let func = quote_spanned!(span=> _serde::export::Default::default); let func = quote_spanned!(span=> _serde::export::Default::default);
return quote_expr!(#func()); return quote_expr!(#func());
} }
attr::Default::Path(ref path) => { attr::Default::Path(path) => {
return quote_expr!(#path()); return quote_expr!(#path());
} }
attr::Default::None => { /* below */ } attr::Default::None => { /* below */ }
@@ -2869,6 +2897,13 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
} }
} }
fn effective_style(variant: &Variant) -> Style {
match variant.style {
Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit,
other => other,
}
}
struct DeImplGenerics<'a>(&'a Parameters); struct DeImplGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
struct InPlaceImplGenerics<'a>(&'a Parameters); struct InPlaceImplGenerics<'a>(&'a Parameters);
@@ -2895,11 +2930,11 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
// Add lifetime for `&'place mut Self, and `'a: 'place` // Add lifetime for `&'place mut Self, and `'a: 'place`
for param in &mut generics.params { for param in &mut generics.params {
match *param { match param {
syn::GenericParam::Lifetime(ref mut param) => { syn::GenericParam::Lifetime(param) => {
param.bounds.push(place_lifetime.lifetime.clone()); param.bounds.push(place_lifetime.lifetime.clone());
} }
syn::GenericParam::Type(ref mut param) => { syn::GenericParam::Type(param) => {
param.bounds.push(syn::TypeParamBound::Lifetime( param.bounds.push(syn::TypeParamBound::Lifetime(
place_lifetime.lifetime.clone(), place_lifetime.lifetime.clone(),
)); ));
+12 -12
View File
@@ -27,9 +27,9 @@ macro_rules! quote_block {
pub struct Expr(pub Fragment); pub struct Expr(pub Fragment);
impl ToTokens for Expr { impl ToTokens for Expr {
fn to_tokens(&self, out: &mut TokenStream) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match &self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out), Fragment::Expr(expr) => expr.to_tokens(out),
Fragment::Block(ref block) => { Fragment::Block(block) => {
token::Brace::default().surround(out, |out| block.to_tokens(out)); token::Brace::default().surround(out, |out| block.to_tokens(out));
} }
} }
@@ -40,9 +40,9 @@ impl ToTokens for Expr {
pub struct Stmts(pub Fragment); pub struct Stmts(pub Fragment);
impl ToTokens for Stmts { impl ToTokens for Stmts {
fn to_tokens(&self, out: &mut TokenStream) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match &self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out), Fragment::Expr(expr) => expr.to_tokens(out),
Fragment::Block(ref block) => block.to_tokens(out), Fragment::Block(block) => block.to_tokens(out),
} }
} }
} }
@@ -52,12 +52,12 @@ impl ToTokens for Stmts {
pub struct Match(pub Fragment); pub struct Match(pub Fragment);
impl ToTokens for Match { impl ToTokens for Match {
fn to_tokens(&self, out: &mut TokenStream) { fn to_tokens(&self, out: &mut TokenStream) {
match self.0 { match &self.0 {
Fragment::Expr(ref expr) => { Fragment::Expr(expr) => {
expr.to_tokens(out); expr.to_tokens(out);
<Token![,]>::default().to_tokens(out); <Token![,]>::default().to_tokens(out);
} }
Fragment::Block(ref block) => { Fragment::Block(block) => {
token::Brace::default().surround(out, |out| block.to_tokens(out)); token::Brace::default().surround(out, |out| block.to_tokens(out));
} }
} }
@@ -66,9 +66,9 @@ impl ToTokens for Match {
impl AsRef<TokenStream> for Fragment { impl AsRef<TokenStream> for Fragment {
fn as_ref(&self) -> &TokenStream { fn as_ref(&self) -> &TokenStream {
match *self { match self {
Fragment::Expr(ref expr) => expr, Fragment::Expr(expr) => expr,
Fragment::Block(ref block) => block, Fragment::Block(block) => block,
} }
} }
} }
+15 -17
View File
@@ -67,11 +67,9 @@ impl<'a> Container<'a> {
) -> Option<Container<'a>> { ) -> Option<Container<'a>> {
let mut attrs = attr::Container::from_ast(cx, item); let mut attrs = attr::Container::from_ast(cx, item);
let mut data = match item.data { let mut data = match &item.data {
syn::Data::Enum(ref data) => { syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())) syn::Data::Struct(data) => {
}
syn::Data::Struct(ref data) => {
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
Data::Struct(style, fields) Data::Struct(style, fields)
} }
@@ -82,8 +80,8 @@ impl<'a> Container<'a> {
}; };
let mut has_flatten = false; let mut has_flatten = false;
match data { match &mut data {
Data::Enum(ref mut variants) => { Data::Enum(variants) => {
for variant in variants { for variant in variants {
variant.attrs.rename_by_rules(attrs.rename_all_rules()); variant.attrs.rename_by_rules(attrs.rename_all_rules());
for field in &mut variant.fields { for field in &mut variant.fields {
@@ -96,7 +94,7 @@ impl<'a> Container<'a> {
} }
} }
} }
Data::Struct(_, ref mut fields) => { Data::Struct(_, fields) => {
for field in fields { for field in fields {
if field.attrs.flatten() { if field.attrs.flatten() {
has_flatten = true; has_flatten = true;
@@ -124,11 +122,11 @@ impl<'a> Container<'a> {
impl<'a> Data<'a> { impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> { pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
match *self { match self {
Data::Enum(ref variants) => { Data::Enum(variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
} }
Data::Struct(_, ref fields) => Box::new(fields.iter()), Data::Struct(_, fields) => Box::new(fields.iter()),
} }
} }
@@ -165,16 +163,16 @@ fn struct_from_ast<'a>(
attrs: Option<&attr::Variant>, attrs: Option<&attr::Variant>,
container_default: &attr::Default, container_default: &attr::Default,
) -> (Style, Vec<Field<'a>>) { ) -> (Style, Vec<Field<'a>>) {
match *fields { match fields {
syn::Fields::Named(ref fields) => ( syn::Fields::Named(fields) => (
Style::Struct, Style::Struct,
fields_from_ast(cx, &fields.named, attrs, container_default), fields_from_ast(cx, &fields.named, attrs, container_default),
), ),
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => ( syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
Style::Newtype, Style::Newtype,
fields_from_ast(cx, &fields.unnamed, attrs, container_default), fields_from_ast(cx, &fields.unnamed, attrs, container_default),
), ),
syn::Fields::Unnamed(ref fields) => ( syn::Fields::Unnamed(fields) => (
Style::Tuple, Style::Tuple,
fields_from_ast(cx, &fields.unnamed, attrs, container_default), fields_from_ast(cx, &fields.unnamed, attrs, container_default),
), ),
@@ -192,8 +190,8 @@ fn fields_from_ast<'a>(
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, field)| Field { .map(|(i, field)| Field {
member: match field.ident { member: match &field.ident {
Some(ref ident) => syn::Member::Named(ident.clone()), Some(ident) => syn::Member::Named(ident.clone()),
None => syn::Member::Unnamed(i.into()), None => syn::Member::Unnamed(i.into()),
}, },
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
File diff suppressed because it is too large Load Diff
+44 -36
View File
@@ -13,6 +13,7 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_internal_tag_field_name_conflict(cx, cont); check_internal_tag_field_name_conflict(cx, cont);
check_adjacent_tag_conflict(cx, cont); check_adjacent_tag_conflict(cx, cont);
check_transparent(cx, cont, derive); check_transparent(cx, cont, derive);
check_from_and_try_from(cx, cont);
} }
/// Getters are only allowed inside structs (not enums) with the `remote` /// Getters are only allowed inside structs (not enums) with the `remote`
@@ -31,8 +32,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
if cont.data.has_getter() && cont.attrs.remote().is_none() { if cont.data.has_getter() && cont.attrs.remote().is_none() {
cx.error_spanned_by( cx.error_spanned_by(
cont.original, cont.original,
"#[serde(getter = \"...\")] can only be used in structs \ "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]",
that have #[serde(remote = \"...\")]",
); );
} }
} }
@@ -41,17 +41,17 @@ 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) { fn check_flatten(cx: &Ctxt, cont: &Container) {
match cont.data { match &cont.data {
Data::Enum(ref variants) => { Data::Enum(variants) => {
for variant in variants { for variant in variants {
for field in &variant.fields { for field in &variant.fields {
check_flatten_field(cx, variant.style, field); check_flatten_field(cx, variant.style, field);
} }
} }
} }
Data::Struct(style, ref fields) => { Data::Struct(style, fields) => {
for field in fields { for field in fields {
check_flatten_field(cx, style, field); check_flatten_field(cx, *style, field);
} }
} }
} }
@@ -85,8 +85,8 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
/// `field_identifier` all but possibly one variant must be unit variants. The /// `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. /// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) { fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match cont.data { let variants = match &cont.data {
Data::Enum(ref variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => {
return; return;
} }
@@ -169,8 +169,8 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
/// Skip-(de)serializing attributes are not allowed on variants marked /// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with. /// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match cont.data { let variants = match &cont.data {
Data::Enum(ref variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => {
return; return;
} }
@@ -182,8 +182,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by( cx.error_spanned_by(
variant.original, variant.original,
format!( format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]",
#[serde(skip_serializing)]",
variant.ident variant.ident
), ),
); );
@@ -196,8 +195,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by( cx.error_spanned_by(
variant.original, variant.original,
format!( format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]",
a field {} marked with #[serde(skip_serializing)]",
variant.ident, member variant.ident, member
), ),
); );
@@ -207,8 +205,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by( cx.error_spanned_by(
variant.original, variant.original,
format!( format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]",
a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, member variant.ident, member
), ),
); );
@@ -221,8 +218,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by( cx.error_spanned_by(
variant.original, variant.original,
format!( format!(
"variant `{}` cannot have both #[serde(deserialize_with)] and \ "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]",
#[serde(skip_deserializing)]",
variant.ident variant.ident
), ),
); );
@@ -235,8 +231,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error_spanned_by( cx.error_spanned_by(
variant.original, variant.original,
format!( format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \ "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]",
and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, member variant.ident, member
), ),
); );
@@ -251,13 +246,13 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
/// duplicate keys in the serialized output and/or ambiguity in /// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input. /// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
let variants = match cont.data { let variants = match &cont.data {
Data::Enum(ref variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => return, Data::Struct(_, _) => return,
}; };
let tag = match *cont.attrs.tag() { let tag = match cont.attrs.tag() {
TagType::Internal { ref tag } => tag.as_str(), TagType::Internal { tag } => tag.as_str(),
TagType::External | TagType::Adjacent { .. } | TagType::None => return, TagType::External | TagType::Adjacent { .. } | TagType::None => return,
}; };
@@ -298,11 +293,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
/// In the case of adjacently-tagged enums, the type and the /// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason. /// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match *cont.attrs.tag() { let (type_tag, content_tag) = match cont.attrs.tag() {
TagType::Adjacent { TagType::Adjacent { tag, content } => (tag, content),
ref tag,
ref content,
} => (tag, content),
TagType::Internal { .. } | TagType::External | TagType::None => return, TagType::Internal { .. } | TagType::External | TagType::None => return,
}; };
@@ -330,6 +322,13 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
); );
} }
if cont.attrs.type_try_from().is_some() {
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]",
);
}
if cont.attrs.type_into().is_some() { if cont.attrs.type_into().is_some() {
cx.error_spanned_by( cx.error_spanned_by(
cont.original, cont.original,
@@ -337,7 +336,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
); );
} }
let fields = match cont.data { let fields = match &mut cont.data {
Data::Enum(_) => { Data::Enum(_) => {
cx.error_spanned_by( cx.error_spanned_by(
cont.original, cont.original,
@@ -352,7 +351,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
); );
return; return;
} }
Data::Struct(_, ref mut fields) => fields, Data::Struct(_, fields) => fields,
}; };
let mut transparent_field = None; let mut transparent_field = None;
@@ -390,16 +389,16 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
} }
fn member_message(member: &Member) -> String { fn member_message(member: &Member) -> String {
match *member { match member {
Member::Named(ref ident) => format!("`{}`", ident), Member::Named(ident) => format!("`{}`", ident),
Member::Unnamed(ref i) => format!("#{}", i.index), Member::Unnamed(i) => format!("#{}", i.index),
} }
} }
fn allow_transparent(field: &Field, derive: Derive) -> bool { fn allow_transparent(field: &Field, derive: Derive) -> bool {
if let Type::Path(ref ty) = *field.ty { if let Type::Path(ty) = field.ty {
if let Some(seg) = ty.path.segments.last() { if let Some(seg) = ty.path.segments.last() {
if seg.into_value().ident == "PhantomData" { if seg.ident == "PhantomData" {
return false; return false;
} }
} }
@@ -410,3 +409,12 @@ fn allow_transparent(field: &Field, derive: Derive) -> bool {
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
} }
} }
fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() {
cx.error_spanned_by(
cont.original,
"#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other",
);
}
}
+5
View File
@@ -38,6 +38,11 @@ impl Ctxt {
.push(syn::Error::new_spanned(obj.into_token_stream(), msg)); .push(syn::Error::new_spanned(obj.into_token_stream(), msg));
} }
/// Add one of Syn's parse errors.
pub fn syn_error(&self, err: syn::Error) {
self.errors.borrow_mut().as_mut().unwrap().push(err);
}
/// Consume this object, producing a formatted error string if there are errors. /// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> Result<(), Vec<syn::Error>> { pub fn check(self) -> Result<(), Vec<syn::Error>> {
let errors = self.errors.borrow_mut().take().unwrap(); let errors = self.errors.borrow_mut().take().unwrap();
+1
View File
@@ -6,6 +6,7 @@ pub use self::ctxt::Ctxt;
mod case; mod case;
mod check; mod check;
mod symbol;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Derive { pub enum Derive {
+67
View File
@@ -0,0 +1,67 @@
use std::fmt::{self, Display};
use syn::{Ident, Path};
#[derive(Copy, Clone)]
pub struct Symbol(&'static str);
pub const ALIAS: Symbol = Symbol("alias");
pub const BORROW: Symbol = Symbol("borrow");
pub const BOUND: Symbol = Symbol("bound");
pub const CONTENT: Symbol = Symbol("content");
pub const CRATE: Symbol = Symbol("crate");
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 FIELD_IDENTIFIER: Symbol = Symbol("field_identifier");
pub const FLATTEN: Symbol = Symbol("flatten");
pub const FROM: Symbol = Symbol("from");
pub const GETTER: Symbol = Symbol("getter");
pub const INTO: Symbol = Symbol("into");
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 SERDE: Symbol = Symbol("serde");
pub const SERIALIZE: Symbol = Symbol("serialize");
pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with");
pub const SKIP: Symbol = Symbol("skip");
pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing");
pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing");
pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if");
pub const TAG: Symbol = Symbol("tag");
pub const TRANSPARENT: Symbol = Symbol("transparent");
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");
impl PartialEq<Symbol> for Ident {
fn eq(&self, word: &Symbol) -> bool {
self == word.0
}
}
impl<'a> PartialEq<Symbol> for &'a Ident {
fn eq(&self, word: &Symbol) -> bool {
*self == word.0
}
}
impl PartialEq<Symbol> for Path {
fn eq(&self, word: &Symbol) -> bool {
self.is_ident(word.0)
}
}
impl<'a> PartialEq<Symbol> for &'a Path {
fn eq(&self, word: &Symbol) -> bool {
self.is_ident(word.0)
}
}
impl Display for Symbol {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.0)
}
}
+5 -1
View File
@@ -13,7 +13,8 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.90")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.103")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints // Ignored clippy lints
@@ -34,6 +35,7 @@
feature = "cargo-clippy", feature = "cargo-clippy",
allow( allow(
cast_possible_truncation, cast_possible_truncation,
checked_conversions,
doc_markdown, doc_markdown,
enum_glob_use, enum_glob_use,
filter_map, filter_map,
@@ -41,8 +43,10 @@
items_after_statements, items_after_statements,
match_same_arms, match_same_arms,
module_name_repetitions, module_name_repetitions,
must_use_candidate,
similar_names, similar_names,
single_match_else, single_match_else,
too_many_lines,
unseparated_literal_suffix, unseparated_literal_suffix,
use_self, use_self,
) )
+5 -5
View File
@@ -52,8 +52,8 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
let type_ident = &cont.ident; let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl(); let (_, ty_generics, _) = cont.generics.split_for_impl();
let patterns = match cont.data { let patterns = match &cont.data {
Data::Enum(ref variants) => variants Data::Enum(variants) => variants
.iter() .iter()
.filter_map(|variant| match variant.style { .filter_map(|variant| match variant.style {
Style::Struct => { Style::Struct => {
@@ -64,7 +64,7 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
_ => None, _ => None,
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, fields) => {
let pat = struct_pattern(fields); let pat = struct_pattern(fields);
vec![quote!(#type_ident #pat)] vec![quote!(#type_ident #pat)]
} }
@@ -93,8 +93,8 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
// } // }
// //
fn pretend_variants_used(cont: &Container) -> TokenStream { fn pretend_variants_used(cont: &Container) -> TokenStream {
let variants = match cont.data { let variants = match &cont.data {
Data::Enum(ref variants) => variants, Data::Enum(variants) => variants,
Data::Struct(_, _) => { Data::Struct(_, _) => {
return quote!(); return quote!();
} }
+41 -47
View File
@@ -16,7 +16,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
None => return Err(ctxt.check().unwrap_err()), None => return Err(ctxt.check().unwrap_err()),
}; };
precondition(&ctxt, &cont); precondition(&ctxt, &cont);
try!(ctxt.check()); ctxt.check()?;
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
@@ -116,7 +116,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Serializer methods. /// various Serializer methods.
fn type_name(&self) -> String { fn type_name(&self) -> String {
self.this.segments.last().unwrap().value().ident.to_string() self.this.segments.last().unwrap().ident.to_string()
} }
} }
@@ -164,15 +164,13 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
} else if let Some(type_into) = cont.attrs.type_into() { } else if let Some(type_into) = cont.attrs.type_into() {
serialize_into(params, type_into) serialize_into(params, type_into)
} else { } else {
match cont.data { match &cont.data {
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs),
serialize_struct(params, fields, &cont.attrs) Data::Struct(Style::Tuple, fields) => {
}
Data::Struct(Style::Tuple, ref fields) => {
serialize_tuple_struct(params, fields, &cont.attrs) serialize_tuple_struct(params, fields, &cont.attrs)
} }
Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Newtype, fields) => {
serialize_newtype_struct(params, &fields[0], &cont.attrs) serialize_newtype_struct(params, &fields[0], &cont.attrs)
} }
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
@@ -181,8 +179,8 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
} }
fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let fields = match cont.data { let fields = match &cont.data {
Data::Struct(_, ref fields) => fields, Data::Struct(_, fields) => fields,
Data::Enum(_) => unreachable!(), Data::Enum(_) => unreachable!(),
}; };
@@ -259,7 +257,7 @@ fn serialize_tuple_struct(
let mut serialized_fields = fields let mut serialized_fields = fields
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing()) .filter(|(_, field)| !field.attrs.skip_serializing())
.peekable(); .peekable();
let let_mut = mut_if(serialized_fields.peek().is_some()); let let_mut = mut_if(serialized_fields.peek().is_some());
@@ -296,8 +294,8 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
} }
fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream { fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream {
match *cattrs.tag() { match cattrs.tag() {
attr::TagType::Internal { ref tag } => { attr::TagType::Internal { tag } => {
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let func = struct_trait.serialize_field(Span::call_site()); let func = struct_trait.serialize_field(Span::call_site());
quote! { quote! {
@@ -467,17 +465,16 @@ fn serialize_variant(
} }
}; };
let body = Match(match *cattrs.tag() { let body = Match(match cattrs.tag() {
attr::TagType::External => { attr::TagType::External => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs) serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
} }
attr::TagType::Internal { ref tag } => { attr::TagType::Internal { tag } => {
serialize_internally_tagged_variant(params, variant, cattrs, tag) serialize_internally_tagged_variant(params, variant, cattrs, tag)
} }
attr::TagType::Adjacent { attr::TagType::Adjacent { tag, content } => {
ref tag, serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
ref content, }
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
attr::TagType::None => serialize_untagged_variant(params, variant, cattrs), attr::TagType::None => serialize_untagged_variant(params, variant, cattrs),
}); });
@@ -509,7 +506,7 @@ fn serialize_externally_tagged_variant(
}; };
} }
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
quote_expr! { quote_expr! {
_serde::Serializer::serialize_unit_variant( _serde::Serializer::serialize_unit_variant(
@@ -586,7 +583,7 @@ fn serialize_internally_tagged_variant(
}; };
} }
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
quote_block! { quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct( let mut __struct = try!(_serde::Serializer::serialize_struct(
@@ -646,7 +643,7 @@ fn serialize_adjacently_tagged_variant(
_serde::Serialize::serialize(#ser, __serializer) _serde::Serialize::serialize(#ser, __serializer)
} }
} else { } else {
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
return quote_block! { return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct( let mut __struct = try!(_serde::Serializer::serialize_struct(
@@ -723,6 +720,8 @@ fn serialize_adjacently_tagged_variant(
where where
__S: _serde::Serializer, __S: _serde::Serializer,
{ {
// Elements that have skip_serializing will be unused.
#[allow(unused_variables)]
let (#(#fields_ident,)*) = self.data; let (#(#fields_ident,)*) = self.data;
#inner #inner
} }
@@ -753,7 +752,7 @@ fn serialize_untagged_variant(
}; };
} }
match variant.style { match effective_style(variant) {
Style::Unit => { Style::Unit => {
quote_expr! { quote_expr! {
_serde::Serializer::serialize_unit(__serializer) _serde::Serializer::serialize_unit(__serializer)
@@ -804,7 +803,7 @@ fn serialize_tuple_variant(
let mut serialized_fields = fields let mut serialized_fields = fields
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing()) .filter(|(_, field)| !field.attrs.skip_serializing())
.peekable(); .peekable();
let let_mut = mut_if(serialized_fields.peek().is_some()); let let_mut = mut_if(serialized_fields.peek().is_some());
@@ -1039,7 +1038,7 @@ fn serialize_tuple_struct_visitor(
fields fields
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, ref field)| !field.attrs.skip_serializing()) .filter(|(_, field)| !field.attrs.skip_serializing())
.map(|(i, field)| { .map(|(i, field)| {
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
let id = Ident::new(&format!("__field{}", i), Span::call_site()); let id = Ident::new(&format!("__field{}", i), Span::call_site());
@@ -1163,9 +1162,9 @@ fn wrap_serialize_variant_with(
.fields .fields
.iter() .iter()
.map(|field| { .map(|field| {
let id = match field.member { let id = match &field.member {
Member::Named(ref ident) => ident.clone(), Member::Named(ident) => ident.clone(),
Member::Unnamed(ref member) => { Member::Unnamed(member) => {
Ident::new(&format!("__field{}", member.index), Span::call_site()) Ident::new(&format!("__field{}", member.index), Span::call_site())
} }
}; };
@@ -1258,6 +1257,13 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea
} }
} }
fn effective_style(variant: &Variant) -> Style {
match variant.style {
Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit,
other => other,
}
}
enum StructTrait { enum StructTrait {
SerializeMap, SerializeMap,
SerializeStruct, SerializeStruct,
@@ -1267,15 +1273,9 @@ enum StructTrait {
impl StructTrait { impl StructTrait {
fn serialize_field(&self, span: Span) -> TokenStream { fn serialize_field(&self, span: Span) -> TokenStream {
match *self { match *self {
StructTrait::SerializeMap => { StructTrait::SerializeMap => quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry),
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) StructTrait::SerializeStruct => quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field),
} StructTrait::SerializeStructVariant => quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field),
StructTrait::SerializeStruct => {
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
}
StructTrait::SerializeStructVariant => {
quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field)
}
} }
} }
@@ -1301,15 +1301,9 @@ enum TupleTrait {
impl TupleTrait { impl TupleTrait {
fn serialize_element(&self, span: Span) -> TokenStream { fn serialize_element(&self, span: Span) -> TokenStream {
match *self { match *self {
TupleTrait::SerializeTuple => { TupleTrait::SerializeTuple => quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element),
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) TupleTrait::SerializeTupleStruct => quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field),
} TupleTrait::SerializeTupleVariant => quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field),
TupleTrait::SerializeTupleStruct => {
quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field)
}
TupleTrait::SerializeTupleVariant => {
quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field)
}
} }
} }
} }
+5 -5
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.24.1" # remember to update html_root_url version = "0.25.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT OR Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable." description = "AST representation used by Serde derive macros. Unstable."
homepage = "https://serde.rs" homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
@@ -14,9 +14,9 @@ include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
proc-macro2 = "0.4" proc-macro2 = "1.0"
quote = "0.6.3" quote = "1.0"
syn = { version = "0.15", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } syn = { version = "1.0", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
+2 -1
View File
@@ -1,4 +1,5 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.24.1")] #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr( #![cfg_attr(
feature = "cargo-clippy", feature = "cargo-clippy",
+2 -2
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.90" # remember to update html_root_url version = "1.0.103" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT OR Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
homepage = "https://serde.rs" homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
-8
View File
@@ -12,7 +12,6 @@ use std::fmt::Debug;
/// # use serde::{Serialize, Deserialize}; /// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_tokens, Token}; /// # use serde_test::{assert_tokens, Token};
/// # /// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S { /// struct S {
/// a: u8, /// a: u8,
@@ -28,7 +27,6 @@ use std::fmt::Debug;
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::StructEnd,
/// ]); /// ]);
/// # }
/// ``` /// ```
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token]) pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where where
@@ -44,7 +42,6 @@ where
/// # use serde::{Serialize, Deserialize}; /// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_ser_tokens, Token}; /// # use serde_test::{assert_ser_tokens, Token};
/// # /// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S { /// struct S {
/// a: u8, /// a: u8,
@@ -60,7 +57,6 @@ where
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::StructEnd,
/// ]); /// ]);
/// # }
/// ``` /// ```
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token]) pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where where
@@ -135,7 +131,6 @@ where
/// # use serde::{Serialize, Deserialize}; /// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens, Token}; /// # use serde_test::{assert_de_tokens, Token};
/// # /// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S { /// struct S {
/// a: u8, /// a: u8,
@@ -151,7 +146,6 @@ where
/// Token::U8(0), /// Token::U8(0),
/// Token::StructEnd, /// Token::StructEnd,
/// ]); /// ]);
/// # }
/// ``` /// ```
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where where
@@ -190,7 +184,6 @@ where
/// # use serde::{Serialize, Deserialize}; /// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens_error, Token}; /// # use serde_test::{assert_de_tokens_error, Token};
/// # /// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// #[serde(deny_unknown_fields)] /// #[serde(deny_unknown_fields)]
/// struct S { /// struct S {
@@ -205,7 +198,6 @@ where
/// ], /// ],
/// "unknown field `x`, expected `a` or `b`", /// "unknown field `x`, expected `a` or `b`",
/// ); /// );
/// # }
/// ``` /// ```
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str) pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where where
+8 -8
View File
@@ -89,11 +89,11 @@ impl<'de> Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let value = try!(visitor.visit_seq(DeserializerSeqVisitor { let value = visitor.visit_seq(DeserializerSeqVisitor {
de: self, de: self,
len: len, len: len,
end: end, end: end,
},)); })?;
assert_next_token!(self, end); assert_next_token!(self, end);
Ok(value) Ok(value)
} }
@@ -107,11 +107,11 @@ impl<'de> Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let value = try!(visitor.visit_map(DeserializerMapVisitor { let value = visitor.visit_map(DeserializerMapVisitor {
de: self, de: self,
len: len, len: len,
end: end, end: end,
},)); })?;
assert_next_token!(self, end); assert_next_token!(self, end);
Ok(value) Ok(value)
} }
@@ -456,11 +456,11 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
| Token::TupleVariant { variant: v, .. } | Token::TupleVariant { variant: v, .. }
| Token::StructVariant { variant: v, .. } => { | Token::StructVariant { variant: v, .. } => {
let de = v.into_deserializer(); let de = v.into_deserializer();
let value = try!(seed.deserialize(de)); let value = seed.deserialize(de)?;
Ok((value, self)) Ok((value, self))
} }
_ => { _ => {
let value = try!(seed.deserialize(&mut *self.de)); let value = seed.deserialize(&mut *self.de)?;
Ok((value, self)) Ok((value, self))
} }
} }
@@ -613,7 +613,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
len: None, len: None,
end: Token::TupleVariantEnd, end: Token::TupleVariantEnd,
}; };
try!(seed.deserialize(SeqAccessDeserializer::new(visitor))) seed.deserialize(SeqAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::TupleVariantEnd); assert_next_token!(self.de, Token::TupleVariantEnd);
Ok(value) Ok(value)
@@ -625,7 +625,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
len: None, len: None,
end: Token::StructVariantEnd, end: Token::StructVariantEnd,
}; };
try!(seed.deserialize(MapAccessDeserializer::new(visitor))) seed.deserialize(MapAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::StructVariantEnd); assert_next_token!(self.de, Token::StructVariantEnd);
Ok(value) Ok(value)
+3 -2
View File
@@ -144,11 +144,11 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.90")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.103")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints // Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
// Ignored clippy_pedantic lints // Ignored clippy_pedantic lints
#![cfg_attr( #![cfg_attr(
feature = "cargo-clippy", feature = "cargo-clippy",
@@ -156,6 +156,7 @@
empty_line_after_outer_attr, empty_line_after_outer_attr,
missing_docs_in_private_items, missing_docs_in_private_items,
module_name_repetitions, module_name_repetitions,
must_use_candidate,
redundant_field_names, redundant_field_names,
use_debug, use_debug,
use_self use_self
+2 -2
View File
@@ -427,7 +427,7 @@ impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> {
where where
T: Serialize, T: Serialize,
{ {
try!(key.serialize(&mut **self)); key.serialize(&mut **self)?;
value.serialize(&mut **self) value.serialize(&mut **self)
} }
@@ -449,7 +449,7 @@ impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> {
where where
T: Serialize, T: Serialize,
{ {
try!(key.serialize(&mut *self.ser)); key.serialize(&mut *self.ser)?;
value.serialize(&mut *self.ser) value.serialize(&mut *self.ser)
} }
+5 -5
View File
@@ -7,14 +7,14 @@ publish = false
[features] [features]
unstable = ["serde/unstable"] unstable = ["serde/unstable"]
compiletest = ["compiletest_rs"]
[dependencies]
serde = { path = "../serde" }
[dev-dependencies] [dev-dependencies]
fnv = "1.0" fnv = "1.0"
rustc-serialize = "0.3.16" rustversion = "0.1"
serde = { path = "../serde", features = ["rc", "derive"] } serde = { path = "../serde", features = ["rc", "derive"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] } serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" } serde_test = { path = "../serde_test" }
trybuild = "1.0"
[dependencies]
compiletest_rs = { version = "0.3", optional = true, features = ["stable"] }
-18
View File
@@ -1,18 +0,0 @@
#### To run unit tests
```sh
cargo test
```
#### To run ui tests
```sh
(cd deps && cargo clean && cargo update && cargo build)
cargo test --features compiletest
```
#### To update goldens after running ui tests
```sh
tests/ui/update-references.sh
```
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "serde_test_suite_deps"
version = "0.0.0"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
[workspace]
[dependencies]
serde = { path = "../../serde" }
serde_derive = { path = "../../serde_derive" }
-3
View File
@@ -1,3 +0,0 @@
#![feature(/*=============================================]
#![=== Serde test suite requires a nightly compiler. ===]
#![====================================================*/)]
+4 -18
View File
@@ -1,21 +1,7 @@
#![cfg(feature = "compiletest")] #[cfg(not(target_os = "emscripten"))]
#[rustversion::attr(not(nightly), ignore)]
use compiletest_rs as compiletest;
#[test] #[test]
fn ui() { fn ui() {
compiletest::run_tests(&compiletest::Config { let t = trybuild::TestCases::new();
mode: compiletest::common::Mode::Ui, t.compile_fail("tests/ui/**/*.rs");
src_base: std::path::PathBuf::from("tests/ui"),
target_rustcflags: Some(String::from(
"\
--edition=2018 \
-L deps/target/debug/deps \
-Z unstable-options \
--extern serde_derive \
",
)),
build_base: std::path::PathBuf::from("../target/ui"),
..Default::default()
});
} }
+28 -6
View File
@@ -4,6 +4,7 @@ use serde::de::{self, MapAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
@@ -1588,14 +1589,35 @@ impl From<Option<u32>> for EnumToU32 {
} }
} }
#[derive(Clone, Deserialize, PartialEq, Debug)]
#[serde(try_from = "u32")]
enum TryFromU32 {
One,
Two,
}
impl TryFrom<u32> for TryFromU32 {
type Error = String;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
1 => Ok(TryFromU32::One),
2 => Ok(TryFromU32::Two),
_ => Err("out of range".to_owned()),
}
}
}
#[test] #[test]
fn test_from_into_traits() { fn test_from_into_traits() {
assert_ser_tokens::<EnumToU32>(&EnumToU32::One, &[Token::Some, Token::U32(1)]); assert_ser_tokens(&EnumToU32::One, &[Token::Some, Token::U32(1)]);
assert_ser_tokens::<EnumToU32>(&EnumToU32::Nothing, &[Token::None]); assert_ser_tokens(&EnumToU32::Nothing, &[Token::None]);
assert_de_tokens::<EnumToU32>(&EnumToU32::Two, &[Token::Some, Token::U32(2)]); assert_de_tokens(&EnumToU32::Two, &[Token::Some, Token::U32(2)]);
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(Some(5)), &[Token::None]); assert_ser_tokens(&StructFromEnum(Some(5)), &[Token::None]);
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(None), &[Token::None]); assert_ser_tokens(&StructFromEnum(None), &[Token::None]);
assert_de_tokens::<StructFromEnum>(&StructFromEnum(Some(2)), &[Token::Some, Token::U32(2)]); assert_de_tokens(&StructFromEnum(Some(2)), &[Token::Some, Token::U32(2)]);
assert_de_tokens(&TryFromU32::Two, &[Token::U32(2)]);
assert_de_tokens_error::<TryFromU32>(&[Token::U32(5)], "out of range");
} }
#[test] #[test]
+116 -6
View File
@@ -1,18 +1,26 @@
#![allow(clippy::decimal_literal_representation)] #![allow(clippy::decimal_literal_representation, clippy::unreadable_literal)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::default::Default; use std::default::Default;
use std::ffi::{CStr, CString, OsString}; use std::ffi::{CStr, CString, OsString};
use std::fmt::Debug;
use std::net; use std::net;
use std::num::Wrapping; use std::num::Wrapping;
use std::ops::Bound; use std::ops::Bound;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak as RcWeak}; use std::rc::{Rc, Weak as RcWeak};
use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize, Ordering,
};
use std::sync::{Arc, Weak as ArcWeak}; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
#[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher; use fnv::FnvHasher;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token}; use serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token};
@@ -95,6 +103,9 @@ struct StructSkipAllDenyUnknown {
a: i32, a: i32,
} }
#[derive(Default, PartialEq, Debug)]
struct NotDeserializable;
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
enum Enum { enum Enum {
#[allow(dead_code)] #[allow(dead_code)]
@@ -108,6 +119,7 @@ enum Enum {
b: i32, b: i32,
c: i32, c: i32,
}, },
SimpleWithSkipped(#[serde(skip_deserializing)] NotDeserializable),
} }
#[derive(PartialEq, Debug, Deserialize)] #[derive(PartialEq, Debug, Deserialize)]
@@ -124,6 +136,19 @@ enum EnumOther {
Other, Other,
} }
#[derive(PartialEq, Debug)]
struct IgnoredAny;
impl<'de> Deserialize<'de> for IgnoredAny {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
serde::de::IgnoredAny::deserialize(deserializer)?;
Ok(IgnoredAny)
}
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
macro_rules! declare_tests { macro_rules! declare_tests {
@@ -706,6 +731,11 @@ declare_tests! {
Token::I32(1), Token::I32(1),
], ],
} }
test_enum_simple_with_skipped {
Enum::SimpleWithSkipped(NotDeserializable) => &[
Token::UnitVariant { name: "Enum", variant: "SimpleWithSkipped" },
],
}
test_enum_seq { test_enum_seq {
Enum::Seq(1, 2, 3) => &[ Enum::Seq(1, 2, 3) => &[
Token::TupleVariant { name: "Enum", variant: "Seq", len: 3 }, Token::TupleVariant { name: "Enum", variant: "Seq", len: 3 },
@@ -858,11 +888,37 @@ declare_tests! {
Path::new("/usr/local/lib") => &[ Path::new("/usr/local/lib") => &[
Token::BorrowedStr("/usr/local/lib"), Token::BorrowedStr("/usr/local/lib"),
], ],
Path::new("/usr/local/lib") => &[
Token::BorrowedBytes(b"/usr/local/lib"),
],
} }
test_path_buf { test_path_buf {
PathBuf::from("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),
],
PathBuf::from("/usr/local/lib") => &[ PathBuf::from("/usr/local/lib") => &[
Token::String("/usr/local/lib"), Token::String("/usr/local/lib"),
], ],
PathBuf::from("/usr/local/lib") => &[
Token::Bytes(b"/usr/local/lib"),
],
PathBuf::from("/usr/local/lib") => &[
Token::ByteBuf(b"/usr/local/lib"),
],
}
test_boxed_path {
PathBuf::from("/usr/local/lib").into_boxed_path() => &[
Token::Str("/usr/local/lib"),
],
PathBuf::from("/usr/local/lib").into_boxed_path() => &[
Token::String("/usr/local/lib"),
],
PathBuf::from("/usr/local/lib").into_boxed_path() => &[
Token::Bytes(b"/usr/local/lib"),
],
PathBuf::from("/usr/local/lib").into_boxed_path() => &[
Token::ByteBuf(b"/usr/local/lib"),
],
} }
test_cstring { test_cstring {
CString::new("abc").unwrap() => &[ CString::new("abc").unwrap() => &[
@@ -929,6 +985,21 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_ignored_any {
IgnoredAny => &[
Token::Str("s"),
],
IgnoredAny => &[
Token::Seq { len: Some(1) },
Token::Bool(true),
Token::SeqEnd,
],
IgnoredAny => &[
Token::Enum { name: "E" },
Token::Str("Rust"),
Token::Unit,
],
}
} }
declare_tests! { declare_tests! {
@@ -1112,6 +1183,45 @@ fn test_never_type() {
); );
} }
#[test]
fn test_atomics() {
fn test<L, A, T>(load: L, val: T, token: Token)
where
L: Fn(&A, Ordering) -> T,
A: DeserializeOwned,
T: PartialEq + Debug,
{
let tokens = &[token];
let mut de = serde_test::Deserializer::new(tokens);
match A::deserialize(&mut de) {
Ok(v) => {
let loaded = load(&v, Ordering::SeqCst);
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));
#[cfg(target_arch = "x86_64")]
{
test(AtomicI64::load, -8589934592, Token::I64(-8589934592));
test(AtomicU64::load, 8589934592u64, Token::U64(8589934592));
}
}
declare_error_tests! { declare_error_tests! {
test_unknown_field<StructDenyUnknown> { test_unknown_field<StructDenyUnknown> {
&[ &[
@@ -1141,13 +1251,13 @@ declare_error_tests! {
&[ &[
Token::UnitVariant { name: "Enum", variant: "Foo" }, Token::UnitVariant { name: "Enum", variant: "Foo" },
], ],
"unknown variant `Foo`, expected one of `Unit`, `Simple`, `Seq`, `Map`", "unknown variant `Foo`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`",
} }
test_enum_skipped_variant<Enum> { test_enum_skipped_variant<Enum> {
&[ &[
Token::UnitVariant { name: "Enum", variant: "Skipped" }, Token::UnitVariant { name: "Enum", variant: "Skipped" },
], ],
"unknown variant `Skipped`, expected one of `Unit`, `Simple`, `Seq`, `Map`", "unknown variant `Skipped`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`",
} }
test_enum_skip_all<EnumSkipAll> { test_enum_skip_all<EnumSkipAll> {
&[ &[
@@ -1178,10 +1288,10 @@ declare_error_tests! {
test_enum_out_of_range<Enum> { test_enum_out_of_range<Enum> {
&[ &[
Token::Enum { name: "Enum" }, Token::Enum { name: "Enum" },
Token::U32(4), Token::U32(5),
Token::Unit, Token::Unit,
], ],
"invalid value: integer `4`, expected variant index 0 <= i < 4", "invalid value: integer `5`, expected variant index 0 <= i < 5",
} }
test_short_tuple<(u8, u8, u8)> { test_short_tuple<(u8, u8, u8)> {
&[ &[
+104
View File
@@ -0,0 +1,104 @@
use serde::de::value::{Error, MapDeserializer, SeqDeserializer};
use serde::de::{
DeserializeSeed, EnumAccess, IgnoredAny, IntoDeserializer, VariantAccess, Visitor,
};
use serde::{forward_to_deserialize_any, Deserialize, Deserializer};
#[derive(PartialEq, Debug, Deserialize)]
enum Target {
Unit,
Newtype(i32),
Tuple(i32, i32),
Struct { a: i32 },
}
struct Enum(&'static str);
impl<'de> Deserializer<'de> for Enum {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
impl<'de> EnumAccess<'de> for Enum {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let v = seed.deserialize(self.0.into_deserializer())?;
Ok((v, self))
}
}
impl<'de> VariantAccess<'de> for Enum {
type Error = Error;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(10i32.into_deserializer())
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let seq = SeqDeserializer::new(vec![1i32, 2].into_iter());
visitor.visit_seq(seq)
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let map = MapDeserializer::new(vec![("a", 10i32)].into_iter());
visitor.visit_map(map)
}
}
#[test]
fn test_deserialize_enum() {
// First just make sure the Deserializer impl works
assert_eq!(Target::Unit, Target::deserialize(Enum("Unit")).unwrap());
assert_eq!(
Target::Newtype(10),
Target::deserialize(Enum("Newtype")).unwrap()
);
assert_eq!(
Target::Tuple(1, 2),
Target::deserialize(Enum("Tuple")).unwrap()
);
assert_eq!(
Target::Struct { a: 10 },
Target::deserialize(Enum("Struct")).unwrap()
);
// Now try IgnoredAny
IgnoredAny::deserialize(Enum("Unit")).unwrap();
IgnoredAny::deserialize(Enum("Newtype")).unwrap();
IgnoredAny::deserialize(Enum("Tuple")).unwrap();
IgnoredAny::deserialize(Enum("Struct")).unwrap();
}
+31 -5
View File
@@ -637,7 +637,10 @@ fn test_untagged_enum() {
], ],
); );
// Serializes to unit, deserializes from either depending on format's
// preference.
assert_tokens(&Untagged::C, &[Token::Unit]); assert_tokens(&Untagged::C, &[Token::Unit]);
assert_de_tokens(&Untagged::C, &[Token::None]);
assert_tokens(&Untagged::D(4), &[Token::U8(4)]); assert_tokens(&Untagged::D(4), &[Token::U8(4)]);
assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]); assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]);
@@ -652,11 +655,6 @@ fn test_untagged_enum() {
], ],
); );
assert_de_tokens_error::<Untagged>(
&[Token::None],
"data did not match any variant of untagged enum Untagged",
);
assert_de_tokens_error::<Untagged>( assert_de_tokens_error::<Untagged>(
&[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd], &[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd],
"data did not match any variant of untagged enum Untagged", "data did not match any variant of untagged enum Untagged",
@@ -1466,6 +1464,34 @@ fn test_internally_tagged_struct_with_flattened_field() {
); );
} }
#[test]
fn test_untagged_enum_with_flattened_integer_key() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Untagged {
Variant {
#[serde(flatten)]
map: BTreeMap<u64, String>,
},
}
assert_tokens(
&Untagged::Variant {
map: {
let mut map = BTreeMap::new();
map.insert(100, "BTreeMap".to_owned());
map
},
},
&[
Token::Map { len: None },
Token::U64(100),
Token::Str("BTreeMap"),
Token::MapEnd,
],
);
}
#[test] #[test]
fn test_enum_in_untagged_enum() { fn test_enum_in_untagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
+41 -3
View File
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "unstable", feature(never_type))] #![allow(clippy::unreadable_literal)]
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
@@ -9,11 +9,17 @@ use std::num::Wrapping;
use std::ops::Bound; use std::ops::Bound;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak as RcWeak}; use std::rc::{Rc, Weak as RcWeak};
use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize,
};
use std::sync::{Arc, Weak as ArcWeak}; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
#[cfg(unix)] #[cfg(unix)]
use std::str; use std::str;
#[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher; use fnv::FnvHasher;
use serde::Serialize; use serde::Serialize;
@@ -37,6 +43,9 @@ struct Struct {
c: i32, c: i32,
} }
#[derive(PartialEq, Debug)]
struct NotSerializable;
#[derive(Serialize, PartialEq, Debug)] #[derive(Serialize, PartialEq, Debug)]
enum Enum { enum Enum {
Unit, Unit,
@@ -57,6 +66,7 @@ enum Enum {
_a: i32, _a: i32,
_b: i32, _b: i32,
}, },
OneWithSkipped(#[serde(skip_serializing)] NotSerializable),
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -302,8 +312,13 @@ declare_tests! {
], ],
} }
test_enum { test_enum {
Enum::Unit => &[Token::UnitVariant { name: "Enum", variant: "Unit" }], Enum::Unit => &[
Enum::One(42) => &[Token::NewtypeVariant { name: "Enum", variant: "One" }, Token::I32(42)], Token::UnitVariant { name: "Enum", variant: "Unit" },
],
Enum::One(42) => &[
Token::NewtypeVariant { name: "Enum", variant: "One" },
Token::I32(42),
],
Enum::Seq(1, 2) => &[ Enum::Seq(1, 2) => &[
Token::TupleVariant { name: "Enum", variant: "Seq", len: 2 }, Token::TupleVariant { name: "Enum", variant: "Seq", len: 2 },
Token::I32(1), Token::I32(1),
@@ -319,6 +334,9 @@ declare_tests! {
Token::I32(2), Token::I32(2),
Token::StructVariantEnd, Token::StructVariantEnd,
], ],
Enum::OneWithSkipped(NotSerializable) => &[
Token::UnitVariant { name: "Enum", variant: "OneWithSkipped" },
],
} }
test_box { test_box {
Box::new(0i32) => &[Token::I32(0)], Box::new(0i32) => &[Token::I32(0)],
@@ -483,6 +501,26 @@ declare_tests! {
Token::Str("1a"), Token::Str("1a"),
], ],
} }
test_atomic {
AtomicBool::new(false) => &[Token::Bool(false)],
AtomicBool::new(true) => &[Token::Bool(true)],
AtomicI8::new(63i8) => &[Token::I8(63i8)],
AtomicI16::new(-318i16) => &[Token::I16(-318i16)],
AtomicI32::new(65792i32) => &[Token::I32(65792i32)],
AtomicIsize::new(-65792isize) => &[Token::I64(-65792i64)],
AtomicU8::new(192u8) => &[Token::U8(192u8)],
AtomicU16::new(510u16) => &[Token::U16(510u16)],
AtomicU32::new(131072u32) => &[Token::U32(131072u32)],
AtomicUsize::new(655360usize) => &[Token::U64(655360u64)],
}
}
#[cfg(target_arch = "x86_64")]
declare_tests! {
test_atomic64 {
AtomicI64::new(-4295032832i64) => &[Token::I64(-4295032832i64)],
AtomicU64::new(12884901888u64) => &[Token::U64(12884901888u64)],
}
} }
declare_tests! { declare_tests! {
+62 -2
View File
@@ -1,5 +1,8 @@
use serde::de::{value, IntoDeserializer}; use serde::de::value::{self, MapAccessDeserializer};
use serde::Deserialize; use serde::de::{IntoDeserializer, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, Token};
use std::fmt;
#[test] #[test]
fn test_u32_to_enum() { fn test_u32_to_enum() {
@@ -32,3 +35,60 @@ fn test_integer128() {
// i128 to i128 // i128 to i128
assert_eq!(1i128, i128::deserialize(de_i128).unwrap()); assert_eq!(1i128, i128::deserialize(de_i128).unwrap());
} }
#[test]
fn test_map_access_to_enum() {
#[derive(PartialEq, Debug)]
struct Potential(PotentialKind);
#[derive(PartialEq, Debug, Deserialize)]
enum PotentialKind {
Airebo(Airebo),
}
#[derive(PartialEq, Debug, Deserialize)]
struct Airebo {
lj_sigma: f64,
}
impl<'de> Deserialize<'de> for Potential {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PotentialVisitor;
impl<'de> Visitor<'de> for PotentialVisitor {
type Value = Potential;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a map")
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
Deserialize::deserialize(MapAccessDeserializer::new(map)).map(Potential)
}
}
deserializer.deserialize_any(PotentialVisitor)
}
}
let expected = Potential(PotentialKind::Airebo(Airebo { lj_sigma: 14.0 }));
assert_de_tokens(
&expected,
&[
Token::Map { len: Some(1) },
Token::Str("Airebo"),
Token::Map { len: Some(1) },
Token::Str("lj_sigma"),
Token::F64(14.0),
Token::MapEnd,
Token::MapEnd,
],
);
}
@@ -3,6 +3,3 @@ error: failed to parse borrowed lifetimes: "zzz"
| |
5 | #[serde(borrow = "zzz")] 5 | #[serde(borrow = "zzz")]
| ^^^^^ | ^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate borrowed lifetime `'a`
| |
5 | #[serde(borrow = "'a + 'a")] 5 | #[serde(borrow = "'a + 'a")]
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `borrow`
| |
8 | #[serde(borrow)] 8 | #[serde(borrow)]
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: at least one lifetime must be borrowed
| |
5 | #[serde(borrow = "")] 5 | #[serde(borrow = "")]
| ^^ | ^^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: field `s` has no lifetimes to borrow
5 | / #[serde(borrow)] 5 | / #[serde(borrow)]
6 | | s: String, 6 | | s: String,
| |_____________^ | |_____________^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: #[serde(borrow)] may only be used on newtype variants
8 | / #[serde(borrow)] 8 | / #[serde(borrow)]
9 | | S { s: Str<'a> }, 9 | | S { s: Str<'a> },
| |____________________^ | |____________________^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: field `s` does not have lifetime 'b
5 | / #[serde(borrow = "'b")] 5 | / #[serde(borrow = "'b")]
6 | | s: &'a str, 6 | | s: &'a str,
| |______________^ | |______________^
error: aborting due to previous error
@@ -7,6 +7,3 @@ error: enum tags `conflict` for type and content conflict with each other
7 | | B, 7 | | B,
8 | | } 8 | | }
| |_^ | |_^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(flatten)] cannot be used on newtype structs
| |
6 | struct Foo(#[serde(flatten)] HashMap<String, String>); 6 | struct Foo(#[serde(flatten)] HashMap<String, String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(flatten)] cannot be used on tuple structs
| |
6 | struct Foo(u32, #[serde(flatten)] HashMap<String, String>); 6 | struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
@@ -0,0 +1,9 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(from = "u64", try_from = "u64")]
struct S {
a: u8,
}
fn main() {}
@@ -0,0 +1,8 @@
error: #[serde(from = "...")] and #[serde(try_from = "...")] conflict with each other
--> $DIR/from-try-from.rs:4:1
|
4 | / #[serde(from = "u64", try_from = "u64")]
5 | | struct S {
6 | | a: u8,
7 | | }
| |_^
@@ -9,6 +9,3 @@ error: variant field name `conflict` conflicts with internal tag
9 | | }, 9 | | },
10 | | } 10 | | }
| |_^ | |_^
error: aborting due to previous error
@@ -9,6 +9,3 @@ error: variant field name `conflict` conflicts with internal tag
9 | | }, 9 | | },
10 | | } 10 | | }
| |_^ | |_^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(default)] can only be used on structs with named fields
| |
5 | enum E { 5 | enum E {
| ^^^^ | ^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(default = "...")] can only be used on structs with named fields
| |
5 | enum E { 5 | enum E {
| ^^^^ | ^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(default)] can only be used on structs with named fields
| |
5 | struct T(u8, u8); 5 | struct T(u8, u8);
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(default = "...")] can only be used on structs with named fields
| |
5 | struct T(u8, u8); 5 | struct T(u8, u8);
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: unknown serde field attribute `serialize`
| |
5 | #[serde(rename = "x", serialize = "y")] 5 | #[serde(rename = "x", serialize = "y")]
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `rename`
| |
5 | #[serde(rename(serialize = "x"), rename(serialize = "y"))] 5 | #[serde(rename(serialize = "x"), rename(serialize = "y"))]
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `rename`
| |
6 | #[serde(rename = "y")] 6 | #[serde(rename = "y")]
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `rename`
| |
5 | #[serde(rename(serialize = "x", serialize = "y"))] 5 | #[serde(rename(serialize = "x", serialize = "y"))]
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `rename`
| |
6 | #[serde(rename(serialize = "y"))] 6 | #[serde(rename(serialize = "y"))]
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: duplicate serde attribute `serialize_with`
| |
5 | #[serde(with = "w", serialize_with = "s")] 5 | #[serde(with = "w", serialize_with = "s")]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(tag = "...", content = "...")] must be used together
| |
4 | #[serde(content = "c")] 4 | #[serde(content = "c")]
| ^^^^^^^ | ^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(tag = "...")] cannot be used with tuple variants
| |
6 | Tuple(u8, u8), 6 | Tuple(u8, u8),
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: aborting due to previous error
@@ -15,6 +15,3 @@ error: untagged enum cannot have #[serde(tag = "...", content = "...")]
| |
5 | #[serde(tag = "t", content = "c")] 5 | #[serde(tag = "t", content = "c")]
| ^^^^^^^ | ^^^^^^^
error: aborting due to 3 previous errors
@@ -9,6 +9,3 @@ error: untagged enum cannot have #[serde(content = "...")]
| |
5 | #[serde(content = "c")] 5 | #[serde(content = "c")]
| ^^^^^^^ | ^^^^^^^
error: aborting due to 2 previous errors
@@ -9,6 +9,3 @@ error: enum cannot be both untagged and internally tagged
| |
5 | #[serde(tag = "type")] 5 | #[serde(tag = "type")]
| ^^^ | ^^^
error: aborting due to 2 previous errors
@@ -3,6 +3,3 @@ error: #[serde(untagged)] can only be used on enums
| |
5 | struct S; 5 | struct S;
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = true)] 5 | #[serde(rename = true)]
| ^^^^ | ^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = b'a')] 5 | #[serde(rename = b'a')]
| ^^^^ | ^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = b"byte string")] 5 | #[serde(rename = b"byte string")]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = 'a')] 5 | #[serde(rename = 'a')]
| ^^^ | ^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = 3.14)] 5 | #[serde(rename = 3.14)]
| ^^^^ | ^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: expected serde rename attribute to be a string: `rename = "..."`
| |
5 | #[serde(rename = 100)] 5 | #[serde(rename = 100)]
| ^^^ | ^^^
error: aborting due to previous error
@@ -9,6 +9,3 @@ error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both b
| |
4 | #[serde(field_identifier, variant_identifier)] 4 | #[serde(field_identifier, variant_identifier)]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
@@ -3,6 +3,3 @@ error: #[serde(field_identifier)] can only be used on an enum
| |
5 | struct S; 5 | struct S;
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(field_identifier)] may only contain unit variants
| |
7 | B(u8, u8), 7 | B(u8, u8),
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: `Other` must be the last variant
| |
7 | Other(String), 7 | Other(String),
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: #[serde(other)] must be on a unit variant
7 | / #[serde(other)] 7 | / #[serde(other)]
8 | | Other(u8, u8), 8 | | Other(u8, u8),
| |_________________^ | |_________________^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: #[serde(other)] must be on the last variant
7 | / #[serde(other)] 7 | / #[serde(other)]
8 | | Other, 8 | | Other,
| |_________^ | |_________^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: #[serde(other)] cannot appear on untagged enum
6 | / #[serde(other)] 6 | / #[serde(other)]
7 | | Other, 7 | | Other,
| |_________^ | |_________^
error: aborting due to previous error
@@ -4,6 +4,3 @@ error: #[serde(other)] may not be used on a variant identifier
6 | / #[serde(other)] 6 | / #[serde(other)]
7 | | Other, 7 | | Other,
| |_________^ | |_________^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(variant_identifier)] can only be used on an enum
| |
5 | struct S; 5 | struct S;
| ^^^^^^ | ^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: #[serde(variant_identifier)] may only contain unit variants
| |
7 | B(u8, u8), 7 | B(u8, u8),
| ^^^^^^^^^ | ^^^^^^^^^
error: aborting due to previous error
@@ -3,6 +3,3 @@ error: malformed bound attribute, expected `bound(serialize = ..., deserialize =
| |
5 | #[serde(bound(unknown))] 5 | #[serde(bound(unknown))]
| ^^^^^^^ | ^^^^^^^
error: aborting due to previous error
+7
View File
@@ -0,0 +1,7 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(rename =)]
struct S;
fn main() {}
@@ -0,0 +1,5 @@
error: unexpected end of input, expected literal
--> $DIR/cut_off.rs:4:17
|
4 | #[serde(rename =)]
| ^
@@ -0,0 +1,8 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde]
#[serde = "?"]
struct S;
fn main() {}
@@ -0,0 +1,11 @@
error: expected #[serde(...)]
--> $DIR/not_list.rs:4:3
|
4 | #[serde]
| ^^^^^
error: expected #[serde(...)]
--> $DIR/not_list.rs:5:3
|
5 | #[serde = "?"]
| ^^^^^^^^^^^
@@ -3,6 +3,3 @@ error: malformed rename attribute, expected `rename(serialize = ..., deserialize
| |
5 | #[serde(rename(unknown))] 5 | #[serde(rename(unknown))]
| ^^^^^^^ | ^^^^^^^
error: aborting due to previous error

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