diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..750707701 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 990dadb73..a0b4be0a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,79 +3,80 @@ name: CI on: push: pull_request: + workflow_dispatch: schedule: [cron: "40 1 * * *"] +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + jobs: test: name: Test suite runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - run: cd test_suite && cargo test --features unstable + - uses: actions/upload-artifact@v6 + if: always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true windows: name: Test suite (windows) runs-on: windows-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - run: cd test_suite && cargo test --features unstable -- --skip ui --exact stable: - name: Rust stable + name: Rust ${{matrix.rust}} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [stable, beta] + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} - run: cd serde && cargo build --features rc - run: cd serde && cargo build --no-default-features - - run: cd serde_test && cargo build - - run: cd serde_test && cargo test --features serde/derive,serde/rc - - beta: - name: Rust beta - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@beta - - run: cd serde && cargo build --features rc - - run: cd test_suite && cargo test + - run: cd test_suite/no_std && cargo build nightly: - name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}} + name: Rust nightly${{matrix.os == 'windows' && ' (windows)' || ''}} runs-on: ${{matrix.os}}-latest strategy: fail-fast: false matrix: os: [ubuntu, windows] + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - run: cd serde && cargo build - run: cd serde && cargo build --no-default-features - run: cd serde && cargo build --no-default-features --features alloc - run: cd serde && cargo build --no-default-features --features rc,alloc - - run: cd serde && cargo test --features derive,rc,unstable + - run: cd serde && cargo build --no-default-features --features unstable + - run: cd serde_core && cargo test --features rc,unstable - run: cd test_suite/no_std && cargo build if: matrix.os != 'windows' - - msrv: - name: Rust 1.13.0 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.13.0 - - name: Get timestamp for cache - id: date - run: echo ::set-output name=yearmo::$(date +%Y%m) - - uses: actions/cache@v1 - with: - path: ~/.cargo/registry/index - key: cargo-registry-index-${{steps.date.outputs.yearmo}} - - run: cd serde && cargo build --features rc - - run: cd serde && cargo build --no-default-features - - run: cd serde_test && cargo build + - run: cd serde_derive && cargo check --tests + env: + RUSTFLAGS: --cfg exhaustive ${{env.RUSTFLAGS}} + if: matrix.os != 'windows' build: name: Rust ${{matrix.rust}} @@ -83,81 +84,98 @@ jobs: strategy: fail-fast: false matrix: - rust: [1.19.0, 1.20.0, 1.21.0, 1.25.0, 1.26.0, 1.34.0] - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{matrix.rust}} - - run: cd serde && cargo build --no-default-features - - run: cd serde && cargo build - - more: - name: Rust ${{matrix.rust}} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - rust: [1.27.0, 1.28.0] + rust: [1.56.0, 1.60.0] + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - # Work around failing to parse manifest because editions are unstable. - - run: sed -i /test_suite/d Cargo.toml + - run: sed -i '/"test_suite"/d' Cargo.toml + - run: cd serde && cargo build --features rc - run: cd serde && cargo build --no-default-features + - run: cd serde && cargo build --no-default-features --features alloc - run: cd serde && cargo build derive: - name: Rust 1.31.0 + name: Rust 1.68.0 runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.31.0 + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@1.68.0 + - run: | + sed -i 's/proc-macro2 = { workspace = true/proc-macro2 = { version = "1"/' serde_derive*/Cargo.toml + sed -i 's/quote = { workspace = true/quote = { version = "1"/' serde_derive*/Cargo.toml + sed -i 's/syn = { workspace = true/syn = { version = "2"/' serde_derive*/Cargo.toml + - run: cd serde && cargo check --no-default-features + - run: cd serde && cargo check - run: cd serde_derive && cargo check - alloc: - name: Rust 1.36.0 + minimal: + name: Minimal versions runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.36.0 - - run: cd serde && cargo build --no-default-features --features alloc + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked --workspace - emscripten: - name: Emscripten + doc: + name: Documentation runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - - uses: actions/setup-node@v1 - with: - node-version: 9 - - name: Install cargo-web - run: | - CARGO_WEB_RELEASE=$(curl -L -s -H Accept:application/json https://github.com/koute/cargo-web/releases/latest) - CARGO_WEB_VERSION=$(echo "${CARGO_WEB_RELEASE}" | jq -r .tag_name) - CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/${CARGO_WEB_VERSION}/cargo-web-x86_64-unknown-linux-gnu.gz" - mkdir -p ~/.cargo/bin - curl -L "${CARGO_WEB_URL}" | gzip -d > ~/.cargo/bin/cargo-web - chmod +x ~/.cargo/bin/cargo-web - - run: cd test_suite && cargo web test --target=asmjs-unknown-emscripten --nodejs - continue-on-error: true - - run: cd test_suite && cargo web test --target=wasm32-unknown-emscripten --nodejs - continue-on-error: true + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs -p serde + - run: cargo docs-rs -p serde_core + - run: cargo docs-rs -p serde_derive + - run: cargo docs-rs -p serde_derive_internals clippy: name: Clippy runs-on: ubuntu-latest if: github.event_name != 'pull_request' + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@clippy - # The need for -Aredundant_field_names here is a Clippy bug. - # https://github.com/rust-lang/rust-clippy/issues/5356 - - run: cd serde && cargo clippy --features rc,unstable -- -D clippy::all -A clippy::redundant_field_names - - run: cd serde_derive && cargo clippy -- -D clippy::all - - run: cd serde_test && cargo clippy -- -D clippy::all -A clippy::redundant_field_names - - run: cd test_suite && cargo clippy --tests --features unstable -- -D clippy::all -A clippy::redundant_field_names - - run: cd test_suite/no_std && cargo clippy -- -D clippy::all -A clippy::redundant_field_names + - run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic + - run: cd serde_core && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic + - run: cd serde_derive && cargo clippy -- -Dclippy::all -Dclippy::pedantic + - run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic + - run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic + - run: cd test_suite/no_std && cargo clippy -- -Dclippy::all -Dclippy::pedantic + + miri: + name: Miri + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@miri + with: + toolchain: nightly-2025-05-16 # https://github.com/rust-lang/miri/issues/4323 + - run: cargo miri setup + - run: cd serde_core && cargo miri test --features rc,unstable + env: + MIRIFLAGS: -Zmiri-strict-provenance + - run: cd test_suite && cargo miri test --features unstable + env: + MIRIFLAGS: -Zmiri-strict-provenance + + outdated: + name: Outdated + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --workspace --exit-code 1 diff --git a/.gitignore b/.gitignore index 165eb22d0..e9e21997b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -target/ -**/*.rs.bk -*.sw[po] -Cargo.lock +/target/ +/Cargo.lock diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 271dface2..f63646b6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,29 +27,23 @@ pull request with your changes. If anything does not pass, typically it will be easier to iterate and fix it locally than waiting for the CI servers to run tests for you. -##### In the [`serde`] directory +##### In the [`serde_core`] directory ```sh # Test all the example code in Serde documentation cargo test ``` -##### In the [`test_suite/deps`] directory - -```sh -# This is a prerequisite for running the full test suite -cargo clean && cargo update && cargo build -``` - ##### In the [`test_suite`] directory ```sh # Run the full test suite, including tests of unstable functionality -cargo test --features unstable +cargo +nightly test --features unstable ``` -[`serde`]: https://github.com/serde-rs/serde/tree/master/serde -[`test_suite/deps`]: https://github.com/serde-rs/serde/tree/master/test_suite/deps +Note that this test suite currently only supports running on a nightly compiler. + +[`serde_core`]: https://github.com/serde-rs/serde/tree/master/serde_core [`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite ## Conduct diff --git a/Cargo.toml b/Cargo.toml index cb35f8543..a139b97dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,19 @@ [workspace] members = [ "serde", + "serde_core", "serde_derive", "serde_derive_internals", - "serde_test", "test_suite", ] +resolver = "2" + +[patch.crates-io] +serde = { path = "serde" } +serde_core = { path = "serde_core" } +serde_derive = { path = "serde_derive" } + +[workspace.dependencies] +proc-macro2 = { version = "1.0.74", default-features = false } +quote = { version = "1.0.35", default-features = false } +syn = { version = "2.0.81", default-features = false } diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 16fe87b06..1b5ec8b78 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/README.md b/README.md index 14b00982e..868967998 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.13+]][Rust 1.13] [![serde_derive: rustc 1.31+]][Rust 1.31] +# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.68] -[Build Status]: https://img.shields.io/github/workflow/status/serde-rs/serde/CI/master +[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master [actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster [Latest Version]: https://img.shields.io/crates/v/serde.svg [crates.io]: https://crates.io/crates/serde -[serde: rustc 1.13+]: https://img.shields.io/badge/serde-rustc_1.13+-lightgray.svg -[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 msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray +[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray +[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0/ +[Rust 1.68]: https://blog.rust-lang.org/2023/03/09/Rust-1.68.0/ **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** @@ -15,11 +15,11 @@ You may be looking for: -- [An overview of Serde](https://serde.rs/) +- [An overview of Serde](https://serde.rs) - [Data formats supported by Serde](https://serde.rs/#data-formats) - [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) - [Examples](https://serde.rs/examples.html) -- [API documentation](https://docs.serde.rs/serde/) +- [API documentation](https://docs.rs/serde) - [Release notes](https://github.com/serde-rs/serde/releases) ## Serde in action @@ -27,7 +27,7 @@ You may be looking for:
Click to show Cargo.toml. -Run this code in the playground. +Run this code in the playground. ```toml @@ -48,7 +48,7 @@ serde_json = "1.0"

```rust -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct Point { @@ -77,17 +77,20 @@ fn main() { Serde is one of the most widely used Rust libraries so any place that Rustaceans congregate will be able to help you out. For chat, consider trying the -[#general] or [#beginners] channels of the unofficial community Discord, the -[#rust-usage] channel of the official Rust Project Discord, or the -[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag -on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned -weekly easy questions post, or the Rust [Discourse forum][discourse]. It's -acceptable to file a support issue in this repo but they tend not to get as many -eyes as any of the above and may get closed without a response after some time. - -[#general]: https://discord.com/channels/273534239310479360/274215136414400513 -[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: ), the [#rust-usage] or +[#beginners] channels of the official Rust Project Discord (invite: +), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 [#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general [stackoverflow]: https://stackoverflow.com/questions/tagged/rust [/r/rust]: https://www.reddit.com/r/rust diff --git a/crates-io.md b/crates-io.md index 07757614a..e6e7d9fb6 100644 --- a/crates-io.md +++ b/crates-io.md @@ -6,17 +6,17 @@ You may be looking for: -- [An overview of Serde](https://serde.rs/) +- [An overview of Serde](https://serde.rs) - [Data formats supported by Serde](https://serde.rs/#data-formats) - [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) - [Examples](https://serde.rs/examples.html) -- [API documentation](https://docs.serde.rs/serde/) +- [API documentation](https://docs.rs/serde) - [Release notes](https://github.com/serde-rs/serde/releases) ## Serde in action ```rust -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct Point { @@ -45,17 +45,20 @@ fn main() { Serde is one of the most widely used Rust libraries so any place that Rustaceans congregate will be able to help you out. For chat, consider trying the -[#general] or [#beginners] channels of the unofficial community Discord, the -[#rust-usage] channel of the official Rust Project Discord, or the -[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag -on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned -weekly easy questions post, or the Rust [Discourse forum][discourse]. It's -acceptable to file a support issue in this repo but they tend not to get as many -eyes as any of the above and may get closed without a response after some time. - -[#general]: https://discord.com/channels/273534239310479360/274215136414400513 -[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: ), the [#rust-usage] +or [#beginners] channels of the official Rust Project Discord (invite: +), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 [#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general [stackoverflow]: https://stackoverflow.com/questions/tagged/rust [/r/rust]: https://www.reddit.com/r/rust diff --git a/serde/Cargo.toml b/serde/Cargo.toml index a04ee8e57..0bffa22d4 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,29 +1,36 @@ [package] name = "serde" -version = "1.0.118" # remember to update html_root_url and serde_derive dependency +version = "1.0.228" authors = ["Erick Tryzelaar ", "David Tolnay "] -license = "MIT OR Apache-2.0" +build = "build.rs" +categories = ["encoding", "no-std", "no-std::no-alloc"] description = "A generic serialization/deserialization framework" +documentation = "https://docs.rs/serde" +edition = "2021" homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" -documentation = "https://docs.serde.rs/serde/" keywords = ["serde", "serialization", "no_std"] -categories = ["encoding"] +license = "MIT OR Apache-2.0" readme = "crates-io.md" -include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] -build = "build.rs" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.56" [dependencies] -serde_derive = { version = "=1.0.118", optional = true, path = "../serde_derive" } - -[dev-dependencies] -serde_derive = { version = "1.0", path = "../serde_derive" } +serde_core = { version = "=1.0.228", path = "../serde_core", default-features = false, features = ["result"] } +serde_derive = { version = "1", optional = true, path = "../serde_derive" } [package.metadata.playground] features = ["derive", "rc"] [package.metadata.docs.rs] +features = ["derive", "rc", "unstable"] targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] ### FEATURES ################################################################# @@ -36,20 +43,20 @@ derive = ["serde_derive"] # Provide impls for common standard library types like Vec and HashMap. # Requires a dependency on the Rust standard library. -std = [] +std = ["serde_core/std"] # Provide impls for types that require unstable functionality. For tracking and # discussion of unstable functionality please refer to this issue: # # https://github.com/serde-rs/serde/issues/812 -unstable = [] +unstable = ["serde_core/unstable"] # Provide impls for types in the Rust core allocation and collections library # including String, Box, Vec, and Cow. This is a subset of std but may # be enabled without depending on all of std. -alloc = [] +alloc = ["serde_core/alloc"] # Opt into impls for Rc and Arc. Serializing and deserializing these types # does not preserve identity and may result in multiple copies of the same data. # Be sure that this is what you want before enabling this feature. -rc = [] +rc = ["serde_core/rc"] diff --git a/serde/build.rs b/serde/build.rs index 613760811..04952346b 100644 --- a/serde/build.rs +++ b/serde/build.rs @@ -1,127 +1,69 @@ use std::env; +use std::fs; +use std::path::PathBuf; use std::process::Command; -use std::str::{self, FromStr}; +use std::str; + +const PRIVATE: &str = "\ +#[doc(hidden)] +pub mod __private$$ { + #[doc(hidden)] + pub use crate::private::*; +} +use serde_core::__private$$ as serde_core_private; +"; // The rustc-cfg strings below are *not* public API. Please let us know by // opening a GitHub issue if your build environment requires some way to enable // these cfgs other than by executing our build script. fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo:rustc-cfg=if_docsrs_then_no_serde_core"); + + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap(); + let module = PRIVATE.replace("$$", &patch_version); + fs::write(out_dir.join("private.rs"), module).unwrap(); + let minor = match rustc_minor_version() { Some(minor) => minor, None => return, }; - let target = env::var("TARGET").unwrap(); - let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; - - // std::collections::Bound was stabilized in Rust 1.17 - // but it was moved to core::ops later in Rust 1.26: - // https://doc.rust-lang.org/core/ops/enum.Bound.html - if minor >= 26 { - println!("cargo:rustc-cfg=ops_bound"); - } else if minor >= 17 && cfg!(feature = "std") { - println!("cargo:rustc-cfg=collections_bound"); - } - - // core::cmp::Reverse stabilized in Rust 1.19: - // https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html - if minor >= 19 { - println!("cargo:rustc-cfg=core_reverse"); - } - - // 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/path/struct.PathBuf.html#method.into_boxed_path - if minor >= 20 { - println!("cargo:rustc-cfg=de_boxed_c_str"); - println!("cargo:rustc-cfg=de_boxed_path"); - } - - // From> for Rc / Arc stabilized in Rust 1.21: - // https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From> - // https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From> - if minor >= 21 { - println!("cargo:rustc-cfg=de_rc_dst"); - } - - // Duration available in core since Rust 1.25: - // https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations - if minor >= 25 { - println!("cargo:rustc-cfg=core_duration"); + if minor >= 77 { + println!("cargo:rustc-check-cfg=cfg(feature, values(\"result\"))"); + println!("cargo:rustc-check-cfg=cfg(if_docsrs_then_no_serde_core)"); + println!("cargo:rustc-check-cfg=cfg(no_core_cstr)"); + println!("cargo:rustc-check-cfg=cfg(no_core_error)"); + println!("cargo:rustc-check-cfg=cfg(no_core_net)"); + println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); + println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); + println!("cargo:rustc-check-cfg=cfg(no_serde_derive)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)"); + println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)"); } - // 128-bit integers stabilized in Rust 1.26: - // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html - // - // Disabled on Emscripten targets as Emscripten doesn't - // currently support integers larger than 64 bits. - if minor >= 26 && !emscripten { - println!("cargo:rustc-cfg=integer128"); + // Current minimum supported version of serde_derive crate is Rust 1.68. + if minor < 68 { + println!("cargo:rustc-cfg=no_serde_derive"); } - // Inclusive ranges methods stabilized in Rust 1.27: - // https://github.com/rust-lang/rust/pull/50758 - if minor >= 27 { - println!("cargo:rustc-cfg=range_inclusive"); - } - - // Non-zero integers stabilized in Rust 1.28: - // https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations - if minor >= 28 { - 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"); - } + // Support for the `#[diagnostic]` tool attribute namespace + // https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes + if minor < 78 { + println!("cargo:rustc-cfg=no_diagnostic_namespace"); } } fn rustc_minor_version() -> Option { - let rustc = match env::var_os("RUSTC") { - Some(rustc) => rustc, - None => return None, - }; - - let output = match Command::new(rustc).arg("--version").output() { - Ok(output) => output, - Err(_) => return None, - }; - - let version = match str::from_utf8(&output.stdout) { - Ok(version) => version, - Err(_) => return None, - }; - + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; let mut pieces = version.split('.'); if pieces.next() != Some("rustc 1") { return None; } - - let next = match pieces.next() { - Some(next) => next, - None => return None, - }; - - u32::from_str(next).ok() + pieces.next()?.parse().ok() } diff --git a/serde/src/core b/serde/src/core new file mode 120000 index 000000000..8c91f5d82 --- /dev/null +++ b/serde/src/core @@ -0,0 +1 @@ +../../serde_core/src \ No newline at end of file diff --git a/serde/src/de/from_primitive.rs b/serde/src/de/from_primitive.rs deleted file mode 100644 index 544f3f1b8..000000000 --- a/serde/src/de/from_primitive.rs +++ /dev/null @@ -1,260 +0,0 @@ -use lib::*; - -macro_rules! int_to_int { - ($dst:ident, $n:ident) => { - if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 { - Some($n as $dst) - } else { - None - } - }; -} - -macro_rules! int_to_uint { - ($dst:ident, $n:ident) => { - if 0 <= $n && $n as u64 <= $dst::max_value() as u64 { - Some($n as $dst) - } else { - None - } - }; -} - -macro_rules! uint_to { - ($dst:ident, $n:ident) => { - if $n as u64 <= $dst::max_value() as u64 { - Some($n as $dst) - } else { - None - } - }; -} - -pub trait FromPrimitive: Sized { - fn from_i8(n: i8) -> Option; - fn from_i16(n: i16) -> Option; - fn from_i32(n: i32) -> Option; - fn from_i64(n: i64) -> Option; - fn from_u8(n: u8) -> Option; - fn from_u16(n: u16) -> Option; - fn from_u32(n: u32) -> Option; - fn from_u64(n: u64) -> Option; -} - -macro_rules! impl_from_primitive_for_int { - ($t:ident) => { - impl FromPrimitive for $t { - #[inline] - fn from_i8(n: i8) -> Option { - int_to_int!($t, n) - } - #[inline] - fn from_i16(n: i16) -> Option { - int_to_int!($t, n) - } - #[inline] - fn from_i32(n: i32) -> Option { - int_to_int!($t, n) - } - #[inline] - fn from_i64(n: i64) -> Option { - int_to_int!($t, n) - } - #[inline] - fn from_u8(n: u8) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u16(n: u16) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u32(n: u32) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u64(n: u64) -> Option { - uint_to!($t, n) - } - } - }; -} - -macro_rules! impl_from_primitive_for_uint { - ($t:ident) => { - impl FromPrimitive for $t { - #[inline] - fn from_i8(n: i8) -> Option { - int_to_uint!($t, n) - } - #[inline] - fn from_i16(n: i16) -> Option { - int_to_uint!($t, n) - } - #[inline] - fn from_i32(n: i32) -> Option { - int_to_uint!($t, n) - } - #[inline] - fn from_i64(n: i64) -> Option { - int_to_uint!($t, n) - } - #[inline] - fn from_u8(n: u8) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u16(n: u16) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u32(n: u32) -> Option { - uint_to!($t, n) - } - #[inline] - fn from_u64(n: u64) -> Option { - uint_to!($t, n) - } - } - }; -} - -macro_rules! impl_from_primitive_for_float { - ($t:ident) => { - impl FromPrimitive for $t { - #[inline] - fn from_i8(n: i8) -> Option { - Some(n as Self) - } - #[inline] - fn from_i16(n: i16) -> Option { - Some(n as Self) - } - #[inline] - fn from_i32(n: i32) -> Option { - Some(n as Self) - } - #[inline] - fn from_i64(n: i64) -> Option { - Some(n as Self) - } - #[inline] - fn from_u8(n: u8) -> Option { - Some(n as Self) - } - #[inline] - fn from_u16(n: u16) -> Option { - Some(n as Self) - } - #[inline] - fn from_u32(n: u32) -> Option { - Some(n as Self) - } - #[inline] - fn from_u64(n: u64) -> Option { - Some(n as Self) - } - } - }; -} - -impl_from_primitive_for_int!(isize); -impl_from_primitive_for_int!(i8); -impl_from_primitive_for_int!(i16); -impl_from_primitive_for_int!(i32); -impl_from_primitive_for_int!(i64); -impl_from_primitive_for_uint!(usize); -impl_from_primitive_for_uint!(u8); -impl_from_primitive_for_uint!(u16); -impl_from_primitive_for_uint!(u32); -impl_from_primitive_for_uint!(u64); -impl_from_primitive_for_float!(f32); -impl_from_primitive_for_float!(f64); - -serde_if_integer128! { - impl FromPrimitive for i128 { - #[inline] - fn from_i8(n: i8) -> Option { - Some(n as i128) - } - #[inline] - fn from_i16(n: i16) -> Option { - Some(n as i128) - } - #[inline] - fn from_i32(n: i32) -> Option { - Some(n as i128) - } - #[inline] - fn from_i64(n: i64) -> Option { - Some(n as i128) - } - #[inline] - fn from_u8(n: u8) -> Option { - Some(n as i128) - } - #[inline] - fn from_u16(n: u16) -> Option { - Some(n as i128) - } - #[inline] - fn from_u32(n: u32) -> Option { - Some(n as i128) - } - #[inline] - fn from_u64(n: u64) -> Option { - Some(n as i128) - } - } - - impl FromPrimitive for u128 { - #[inline] - fn from_i8(n: i8) -> Option { - if n >= 0 { - Some(n as u128) - } else { - None - } - } - #[inline] - fn from_i16(n: i16) -> Option { - if n >= 0 { - Some(n as u128) - } else { - None - } - } - #[inline] - fn from_i32(n: i32) -> Option { - if n >= 0 { - Some(n as u128) - } else { - None - } - } - #[inline] - fn from_i64(n: i64) -> Option { - if n >= 0 { - Some(n as u128) - } else { - None - } - } - #[inline] - fn from_u8(n: u8) -> Option { - Some(n as u128) - } - #[inline] - fn from_u16(n: u16) -> Option { - Some(n as u128) - } - #[inline] - fn from_u32(n: u32) -> Option { - Some(n as u128) - } - #[inline] - fn from_u64(n: u64) -> Option { - Some(n as u128) - } - } -} diff --git a/serde/src/de/utf8.rs b/serde/src/de/utf8.rs deleted file mode 100644 index 576fd03cf..000000000 --- a/serde/src/de/utf8.rs +++ /dev/null @@ -1,46 +0,0 @@ -use lib::*; - -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; - -#[inline] -pub fn encode(c: char) -> Encode { - let code = c as u32; - let mut buf = [0; 4]; - let pos = if code < MAX_ONE_B { - buf[3] = code as u8; - 3 - } else if code < MAX_TWO_B { - buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B { - buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 1 - } else { - buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 0 - }; - Encode { buf: buf, pos: pos } -} - -pub struct Encode { - buf: [u8; 4], - pos: usize, -} - -impl Encode { - pub fn as_str(&self) -> &str { - str::from_utf8(&self.buf[self.pos..]).unwrap() - } -} diff --git a/serde/src/export.rs b/serde/src/export.rs deleted file mode 100644 index caa1f4dc2..000000000 --- a/serde/src/export.rs +++ /dev/null @@ -1,39 +0,0 @@ -pub use lib::clone::Clone; -pub use lib::convert::{From, Into}; -pub use lib::default::Default; -pub use lib::fmt::{self, Formatter}; -pub use lib::marker::PhantomData; -pub use lib::option::Option::{self, None, Some}; -pub use lib::result::Result::{self, Err, Ok}; - -pub use self::string::from_utf8_lossy; - -#[cfg(any(feature = "alloc", feature = "std"))] -pub use lib::{ToString, Vec}; - -#[cfg(core_try_from)] -pub use lib::convert::TryFrom; - -mod string { - use lib::*; - - #[cfg(any(feature = "std", feature = "alloc"))] - pub fn from_utf8_lossy(bytes: &[u8]) -> Cow { - String::from_utf8_lossy(bytes) - } - - // The generated code calls this like: - // - // let value = &_serde::export::from_utf8_lossy(bytes); - // Err(_serde::de::Error::unknown_variant(value, VARIANTS)) - // - // so it is okay for the return type to be different from the std case as long - // as the above works. - #[cfg(not(any(feature = "std", feature = "alloc")))] - pub fn from_utf8_lossy(bytes: &[u8]) -> &str { - // Three unicode replacement characters if it fails. They look like a - // white-on-black question mark. The user will recognize it as invalid - // UTF-8. - str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}") - } -} diff --git a/serde/src/integer128.rs b/serde/src/integer128.rs index 01d6f34a1..c9ff9d64b 100644 --- a/serde/src/integer128.rs +++ b/serde/src/integer128.rs @@ -1,82 +1,14 @@ -/// Conditional compilation depending on whether Serde is built with support for -/// 128-bit integers. -/// -/// Data formats that wish to support Rust compiler versions older than 1.26 -/// (or targets that lack 128-bit integers) may place the i128 / u128 methods -/// of their Serializer and Deserializer behind this macro. -/// -/// Data formats that require a minimum Rust compiler version of at least 1.26, -/// or do not target platforms that lack 128-bit integers, do not need to -/// bother with this macro and may assume support for 128-bit integers. -/// -/// ```edition2018 -/// # use serde::private::ser::Error; -/// # -/// # struct MySerializer; -/// # -/// use serde::{serde_if_integer128, Serializer}; -/// -/// impl Serializer for MySerializer { -/// type Ok = (); -/// type Error = Error; -/// -/// fn serialize_i64(self, v: i64) -> Result { -/// /* ... */ -/// # unimplemented!() -/// } -/// -/// /* ... */ -/// -/// serde_if_integer128! { -/// fn serialize_i128(self, v: i128) -> Result { -/// /* ... */ -/// # unimplemented!() -/// } -/// -/// fn serialize_u128(self, v: u128) -> Result { -/// /* ... */ -/// # unimplemented!() -/// } -/// } -/// # -/// # serde::__serialize_unimplemented! { -/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some -/// # unit unit_struct unit_variant newtype_struct newtype_variant seq -/// # tuple tuple_struct tuple_variant map struct struct_variant -/// # } -/// } -/// ``` -/// -/// When Serde is built with support for 128-bit integers, this macro expands -/// transparently into just the input tokens. -/// -/// ```edition2018 -/// macro_rules! serde_if_integer128 { -/// ($($tt:tt)*) => { -/// $($tt)* -/// }; -/// } -/// ``` -/// -/// When built without support for 128-bit integers, this macro expands to -/// nothing. -/// -/// ```edition2018 -/// macro_rules! serde_if_integer128 { -/// ($($tt:tt)*) => {}; -/// } -/// ``` -#[cfg(integer128)] #[macro_export] +#[deprecated = " +This macro has no effect on any version of Serde released in the past 2 years. +It was used long ago in crates that needed to support Rustc older than 1.26.0, +or Emscripten targets older than 1.40.0, which did not yet have 128-bit integer +support. These days Serde requires a Rust compiler newer than that so 128-bit +integers are always supported. +"] +#[doc(hidden)] macro_rules! serde_if_integer128 { ($($tt:tt)*) => { $($tt)* }; } - -#[cfg(not(integer128))] -#[macro_export] -#[doc(hidden)] -macro_rules! serde_if_integer128 { - ($($tt:tt)*) => {}; -} diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 12154da25..527a680a8 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -9,11 +9,9 @@ //! these two groups interact with each other, allowing any supported data //! structure to be serialized and deserialized using any supported data format. //! -//! See the Serde website [https://serde.rs/] for additional documentation and +//! See the Serde website for additional documentation and //! usage examples. //! -//! [https://serde.rs/]: https://serde.rs/ -//! //! ## Design //! //! Where many other languages rely on runtime reflection for serializing data, @@ -33,8 +31,7 @@ //! for Serde by the community. //! //! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs. -//! - [Bincode], a compact binary format -//! used for IPC within the Servo rendering engine. +//! - [Postcard], a no\_std and embedded-systems friendly compact binary format. //! - [CBOR], a Concise Binary Object Representation designed for small message //! size without the need for version negotiation. //! - [YAML], a self-proclaimed human-friendly configuration language that ain't @@ -46,9 +43,10 @@ //! - [BSON], the data storage and network transfer format used by MongoDB. //! - [Avro], a binary format used within Apache Hadoop, with support for schema //! definition. -//! - [JSON5], A superset of JSON including some productions from ES5. -//! - [Postcard], a no\_std and embedded-systems friendly compact binary format. +//! - [JSON5], a superset of JSON including some productions from ES5. //! - [URL] query strings, in the x-www-form-urlencoded format. +//! - [Starlark], the format used for describing build targets by the Bazel and +//! Buck build systems. *(serialization only)* //! - [Envy], a way to deserialize environment variables into Rust structs. //! *(deserialization only)* //! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into @@ -56,87 +54,113 @@ //! - [S-expressions], the textual representation of code and data used by the //! Lisp language family. //! - [D-Bus]'s binary wire format. -//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format. +//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy +//! serialization format. +//! - [Bencode], a simple binary format used in the BitTorrent protocol. +//! - [Token streams], for processing Rust procedural macro input. +//! *(deserialization only)* +//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to +//! and from DynamoDB. +//! - [Hjson], a syntax extension to JSON designed around human reading and +//! editing. *(deserialization only)* +//! - [CSV], Comma-separated values is a tabular text file format. //! //! [JSON]: https://github.com/serde-rs/json -//! [Bincode]: https://github.com/servo/bincode -//! [CBOR]: https://github.com/pyfisch/cbor +//! [Postcard]: https://github.com/jamesmunns/postcard +//! [CBOR]: https://github.com/enarx/ciborium //! [YAML]: https://github.com/dtolnay/serde-yaml //! [MessagePack]: https://github.com/3Hren/msgpack-rust -//! [TOML]: https://github.com/alexcrichton/toml-rs +//! [TOML]: https://docs.rs/toml //! [Pickle]: https://github.com/birkenfeld/serde-pickle //! [RON]: https://github.com/ron-rs/ron -//! [BSON]: https://github.com/zonyitoo/bson-rs -//! [Avro]: https://github.com/flavray/avro-rs +//! [BSON]: https://github.com/mongodb/bson-rust +//! [Avro]: https://docs.rs/apache-avro //! [JSON5]: https://github.com/callum-oakley/json5-rs -//! [Postcard]: https://github.com/jamesmunns/postcard //! [URL]: https://docs.rs/serde_qs +//! [Starlark]: https://github.com/dtolnay/serde-starlark //! [Envy]: https://github.com/softprops/envy //! [Envy Store]: https://github.com/softprops/envy-store -//! [Cargo]: http://doc.crates.io/manifest.html -//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html +//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html +//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html //! [S-expressions]: https://github.com/rotty/lexpr-rs //! [D-Bus]: https://docs.rs/zvariant //! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers +//! [Bencode]: https://github.com/P3KI/bendy +//! [Token streams]: https://github.com/oxidecomputer/serde_tokenstream +//! [DynamoDB Items]: https://docs.rs/serde_dynamo +//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb +//! [Hjson]: https://github.com/Canop/deser-hjson +//! [CSV]: https://docs.rs/csv //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.118")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.228")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] +// Show which crate feature enables conditionally compiled APIs in documentation. +#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))] +#![cfg_attr(docsrs, allow(internal_features))] // Unstable functionality only if the user asks for it. For tracking and // discussion of these features please refer to this issue: // // https://github.com/serde-rs/serde/issues/812 #![cfg_attr(feature = "unstable", feature(never_type))] -#![allow(unknown_lints, bare_trait_objects, deprecated)] -#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] +#![allow( + unknown_lints, + bare_trait_objects, + deprecated, + mismatched_lifetime_syntaxes +)] // Ignored clippy and clippy_pedantic lints -#![cfg_attr( - feature = "cargo-clippy", - allow( - // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 - unnested_or_patterns, - // not available in our oldest supported compiler - checked_conversions, - empty_enum, - redundant_field_names, - redundant_static_lifetimes, - // integer and float ser/de requires these sorts of casts - cast_possible_truncation, - cast_possible_wrap, - cast_sign_loss, - // things are often more readable this way - cast_lossless, - module_name_repetitions, - option_if_let_else, - single_match_else, - type_complexity, - use_self, - zero_prefixed_literal, - // correctly used - enum_glob_use, - map_err_ignore, - result_unit_err, - wildcard_imports, - // not practical - needless_pass_by_value, - similar_names, - too_many_lines, - // preference - doc_markdown, - unseparated_literal_suffix, - // false positive - needless_doctest_main, - // noisy - missing_errors_doc, - must_use_candidate, - ) +#![allow( + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768 + clippy::semicolon_if_nothing_returned, + // not available in our oldest supported compiler + clippy::empty_enums, + clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772 + // integer and float ser/de requires these sorts of casts + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + // things are often more readable this way + clippy::cast_lossless, + clippy::module_name_repetitions, + clippy::single_match_else, + clippy::type_complexity, + clippy::use_self, + clippy::zero_prefixed_literal, + // correctly used + clippy::derive_partial_eq_without_eq, + clippy::enum_glob_use, + clippy::explicit_auto_deref, + clippy::incompatible_msrv, + clippy::let_underscore_untyped, + clippy::map_err_ignore, + clippy::new_without_default, + clippy::result_unit_err, + clippy::wildcard_imports, + // not practical + clippy::needless_pass_by_value, + clippy::similar_names, + clippy::too_many_lines, + // preference + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::needless_lifetimes, + clippy::unseparated_literal_suffix, + // false positive + clippy::needless_doctest_main, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, )] +// Restrictions +#![deny(clippy::question_mark_used)] // Rustc lints. -#![forbid(unsafe_code)] #![deny(missing_docs, unused_imports)] //////////////////////////////////////////////////////////////////////////////// @@ -144,146 +168,118 @@ #[cfg(feature = "alloc")] extern crate alloc; -/// A facade around all the types we need from the `std`, `core`, and `alloc` -/// crates. This avoids elaborate import wrangling having to happen in every -/// module. -mod lib { - mod core { - #[cfg(not(feature = "std"))] - pub use core::*; - #[cfg(feature = "std")] - pub use std::*; - } - - pub use self::core::{cmp, iter, mem, num, slice, str}; - pub use self::core::{f32, f64}; - pub use self::core::{i16, i32, i64, i8, isize}; - pub use self::core::{u16, u32, u64, u8, usize}; - - pub use self::core::cell::{Cell, RefCell}; - pub use self::core::clone::{self, Clone}; - pub use self::core::convert::{self, From, Into}; - pub use self::core::default::{self, Default}; - pub use self::core::fmt::{self, Debug, Display}; - pub use self::core::marker::{self, PhantomData}; - pub use self::core::num::Wrapping; - pub use self::core::ops::Range; - pub use self::core::option::{self, Option}; - pub use self::core::result::{self, Result}; +// Rustdoc has a lot of shortcomings related to cross-crate re-exports that make +// the rendered documentation of serde_core traits in serde more challenging to +// understand than the equivalent documentation of the same items in serde_core. +// https://github.com/rust-lang/rust/labels/A-cross-crate-reexports +// So, just for the purpose of docs.rs documentation, we inline the contents of +// serde_core into serde. This sidesteps all the cross-crate rustdoc bugs. +#[cfg(docsrs)] +#[macro_use] +#[path = "core/crate_root.rs"] +mod crate_root; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::borrow::{Cow, ToOwned}; - #[cfg(feature = "std")] - pub use std::borrow::{Cow, ToOwned}; +#[cfg(docsrs)] +#[macro_use] +#[path = "core/macros.rs"] +mod macros; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::string::{String, ToString}; - #[cfg(feature = "std")] - pub use std::string::{String, ToString}; +#[cfg(not(docsrs))] +macro_rules! crate_root { + () => { + /// A facade around all the types we need from the `std`, `core`, and `alloc` + /// crates. This avoids elaborate import wrangling having to happen in every + /// module. + mod lib { + mod core { + #[cfg(not(feature = "std"))] + pub use core::*; + #[cfg(feature = "std")] + pub use std::*; + } - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::vec::Vec; - #[cfg(feature = "std")] - pub use std::vec::Vec; + pub use self::core::{f32, f64}; + pub use self::core::{ptr, str}; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::boxed::Box; - #[cfg(feature = "std")] - pub use std::boxed::Box; + #[cfg(any(feature = "std", feature = "alloc"))] + pub use self::core::slice; - #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] - pub use alloc::rc::{Rc, Weak as RcWeak}; - #[cfg(all(feature = "rc", feature = "std"))] - pub use std::rc::{Rc, Weak as RcWeak}; + pub use self::core::clone; + pub use self::core::convert; + pub use self::core::default; + pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite}; + pub use self::core::marker::{self, PhantomData}; + pub use self::core::option; + pub use self::core::result; - #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] - pub use alloc::sync::{Arc, Weak as ArcWeak}; - #[cfg(all(feature = "rc", feature = "std"))] - pub use std::sync::{Arc, Weak as ArcWeak}; + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::borrow::{Cow, ToOwned}; + #[cfg(feature = "std")] + pub use std::borrow::{Cow, ToOwned}; - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; - #[cfg(feature = "std")] - pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::{String, ToString}; - #[cfg(feature = "std")] - pub use std::{error, net}; + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::vec::Vec; + #[cfg(feature = "std")] + pub use std::vec::Vec; - #[cfg(feature = "std")] - pub use std::collections::{HashMap, HashSet}; - #[cfg(feature = "std")] - pub use std::ffi::{CStr, CString, OsStr, OsString}; - #[cfg(feature = "std")] - pub use std::hash::{BuildHasher, Hash}; - #[cfg(feature = "std")] - pub use std::io::Write; - #[cfg(feature = "std")] - pub use std::path::{Path, PathBuf}; - #[cfg(feature = "std")] - pub use std::sync::{Mutex, RwLock}; - #[cfg(feature = "std")] - pub use std::time::{SystemTime, UNIX_EPOCH}; + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::boxed::Box; + #[cfg(feature = "std")] + pub use std::boxed::Box; + } - #[cfg(all(feature = "std", collections_bound))] - pub use std::collections::Bound; + // None of this crate's error handling needs the `From::from` error conversion + // performed implicitly by the `?` operator or the standard library's `try!` + // macro. This simplified macro gives a 5.5% improvement in compile time + // compared to standard `try!`, and 9% improvement compared to `?`. + #[cfg(not(no_serde_derive))] + macro_rules! tri { + ($expr:expr) => { + match $expr { + Ok(val) => val, + Err(err) => return Err(err), + } + }; + } - #[cfg(core_reverse)] - pub use self::core::cmp::Reverse; + //////////////////////////////////////////////////////////////////////////////// - #[cfg(ops_bound)] - pub use self::core::ops::Bound; + pub use serde_core::{ + de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer, + }; - #[cfg(range_inclusive)] - pub use self::core::ops::RangeInclusive; + // Used by generated code and doc tests. Not public API. + #[doc(hidden)] + mod private; - #[cfg(all(feature = "std", std_atomic))] - pub use std::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8, - AtomicUsize, Ordering, + include!(concat!(env!("OUT_DIR"), "/private.rs")); }; - #[cfg(all(feature = "std", std_atomic64))] - pub use std::sync::atomic::{AtomicI64, AtomicU64}; - - #[cfg(any(core_duration, feature = "std"))] - pub use self::core::time::Duration; } -//////////////////////////////////////////////////////////////////////////////// +crate_root!(); -#[macro_use] -mod macros; - -#[macro_use] mod integer128; -pub mod de; -pub mod ser; - -#[doc(inline)] -pub use de::{Deserialize, Deserializer}; -#[doc(inline)] -pub use ser::{Serialize, Serializer}; - -// Generated code uses these to support no_std. Not public API. -#[doc(hidden)] -pub mod export; - -// Helpers used by generated code and doc tests. Not public API. -#[doc(hidden)] -pub mod private; - -#[cfg(not(feature = "std"))] -mod std_error; - // Re-export #[derive(Serialize, Deserialize)]. // // The reason re-exporting is not enabled by default is that disabling it would // be annoying for crates that provide handwritten impls or data formats. They // would need to disable default features and then explicitly re-enable std. #[cfg(feature = "serde_derive")] -#[allow(unused_imports)] -#[macro_use] extern crate serde_derive; + +/// Derive macro available if serde is built with `features = ["derive"]`. #[cfg(feature = "serde_derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] +pub use serde_derive::{Deserialize, Serialize}; + +#[macro_export] #[doc(hidden)] -pub use serde_derive::*; +macro_rules! __require_serde_not_serde_core { + () => {}; +} diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index bcb964a9c..6f657f50e 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -1,17 +1,24 @@ -use lib::*; +use crate::lib::*; -use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; +use crate::de::value::{BorrowedBytesDeserializer, BytesDeserializer}; +use crate::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, VariantAccess, + Visitor, +}; #[cfg(any(feature = "std", feature = "alloc"))] -use de::{MapAccess, Unexpected}; +use crate::de::{MapAccess, Unexpected}; #[cfg(any(feature = "std", feature = "alloc"))] pub use self::content::{ - Content, ContentDeserializer, ContentRefDeserializer, EnumDeserializer, - InternallyTaggedUnitVisitor, TagContentOtherField, TagContentOtherFieldVisitor, - TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor, + content_as_str, Content, ContentDeserializer, ContentRefDeserializer, ContentVisitor, + EnumDeserializer, InternallyTaggedUnitVisitor, TagContentOtherField, + TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, + UntaggedUnitVisitor, }; +pub use crate::serde_core_private::InPlaceSeed; + /// If the missing field is of type `Option` then treat is as `None`, /// otherwise it is an error. pub fn missing_field<'de, V, E>(field: &'static str) -> Result @@ -21,6 +28,7 @@ where { struct MissingFieldDeserializer(&'static str, PhantomData); + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, E> Deserializer<'de> for MissingFieldDeserializer where E: Error, @@ -41,7 +49,7 @@ where visitor.visit_none() } - forward_to_deserialize_any! { + serde_core::forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any @@ -60,6 +68,7 @@ where { struct CowStrVisitor; + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a> Visitor<'a> for CowStrVisitor { type Value = Cow<'a, str>; @@ -133,6 +142,7 @@ where { struct CowBytesVisitor; + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a> Visitor<'a> for CowBytesVisitor { type Value = Cow<'a, [u8]>; @@ -188,29 +198,6 @@ where .map(From::from) } -pub mod size_hint { - use lib::*; - - pub fn from_bounds(iter: &I) -> Option - where - I: Iterator, - { - helper(iter.size_hint()) - } - - #[inline] - pub fn cautious(hint: Option) -> usize { - cmp::min(hint.unwrap_or(0), 4096) - } - - fn helper(bounds: (usize, Option)) -> Option { - match bounds { - (lower, Some(upper)) if lower == upper => Some(upper), - _ => None, - } - } -} - #[cfg(any(feature = "std", feature = "alloc"))] mod content { // This module is private and nothing here should be used outside of @@ -223,111 +210,106 @@ mod content { // This issue is tracking making some of this stuff public: // https://github.com/serde-rs/serde/issues/741 - use lib::*; + use crate::lib::*; - use super::size_hint; - use de::{ + use crate::de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor, }; - - /// Used from generated code to buffer the contents of the Deserializer when - /// deserializing untagged enums and internally tagged enums. - /// - /// Not public API. Use serde-value instead. - #[derive(Debug)] - pub enum Content<'de> { - Bool(bool), - - U8(u8), - U16(u16), - U32(u32), - U64(u64), - - I8(i8), - I16(i16), - I32(i32), - I64(i64), - - F32(f32), - F64(f64), - - Char(char), - String(String), - Str(&'de str), - ByteBuf(Vec), - Bytes(&'de [u8]), - - None, - Some(Box>), - - Unit, - Newtype(Box>), - Seq(Vec>), - Map(Vec<(Content<'de>, Content<'de>)>), - } - - impl<'de> Content<'de> { - pub fn as_str(&self) -> Option<&str> { - match *self { - Content::Str(x) => Some(x), - Content::String(ref x) => Some(x), - Content::Bytes(x) => str::from_utf8(x).ok(), - Content::ByteBuf(ref x) => str::from_utf8(x).ok(), - _ => None, - } - } - - #[cold] - fn unexpected(&self) -> Unexpected { - match *self { - Content::Bool(b) => Unexpected::Bool(b), - Content::U8(n) => Unexpected::Unsigned(n as u64), - Content::U16(n) => Unexpected::Unsigned(n as u64), - Content::U32(n) => Unexpected::Unsigned(n as u64), - Content::U64(n) => Unexpected::Unsigned(n), - Content::I8(n) => Unexpected::Signed(n as i64), - Content::I16(n) => Unexpected::Signed(n as i64), - Content::I32(n) => Unexpected::Signed(n as i64), - Content::I64(n) => Unexpected::Signed(n), - Content::F32(f) => Unexpected::Float(f as f64), - Content::F64(f) => Unexpected::Float(f), - Content::Char(c) => Unexpected::Char(c), - Content::String(ref s) => Unexpected::Str(s), - Content::Str(s) => Unexpected::Str(s), - Content::ByteBuf(ref b) => Unexpected::Bytes(b), - Content::Bytes(b) => Unexpected::Bytes(b), - Content::None | Content::Some(_) => Unexpected::Option, - Content::Unit => Unexpected::Unit, - Content::Newtype(_) => Unexpected::NewtypeStruct, - Content::Seq(_) => Unexpected::Seq, - Content::Map(_) => Unexpected::Map, - } - } - } - - impl<'de> Deserialize<'de> for Content<'de> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // Untagged and internally tagged enums are only supported in - // self-describing formats. - let visitor = ContentVisitor { value: PhantomData }; - deserializer.deserialize_any(visitor) + use crate::serde_core_private::size_hint; + pub use crate::serde_core_private::Content; + + pub fn content_as_str<'a, 'de>(content: &'a Content<'de>) -> Option<&'a str> { + match *content { + Content::Str(x) => Some(x), + Content::String(ref x) => Some(x), + Content::Bytes(x) => str::from_utf8(x).ok(), + Content::ByteBuf(ref x) => str::from_utf8(x).ok(), + _ => None, } } - struct ContentVisitor<'de> { + fn content_clone<'de>(content: &Content<'de>) -> Content<'de> { + match content { + Content::Bool(b) => Content::Bool(*b), + Content::U8(n) => Content::U8(*n), + Content::U16(n) => Content::U16(*n), + Content::U32(n) => Content::U32(*n), + Content::U64(n) => Content::U64(*n), + Content::I8(n) => Content::I8(*n), + Content::I16(n) => Content::I16(*n), + Content::I32(n) => Content::I32(*n), + Content::I64(n) => Content::I64(*n), + Content::F32(f) => Content::F32(*f), + Content::F64(f) => Content::F64(*f), + Content::Char(c) => Content::Char(*c), + Content::String(s) => Content::String(s.clone()), + Content::Str(s) => Content::Str(*s), + Content::ByteBuf(b) => Content::ByteBuf(b.clone()), + Content::Bytes(b) => Content::Bytes(b), + Content::None => Content::None, + Content::Some(content) => Content::Some(Box::new(content_clone(content))), + Content::Unit => Content::Unit, + Content::Newtype(content) => Content::Newtype(Box::new(content_clone(content))), + Content::Seq(seq) => Content::Seq(seq.iter().map(content_clone).collect()), + Content::Map(map) => Content::Map( + map.iter() + .map(|(k, v)| (content_clone(k), content_clone(v))) + .collect(), + ), + } + } + + #[cold] + fn content_unexpected<'a, 'de>(content: &'a Content<'de>) -> Unexpected<'a> { + match *content { + Content::Bool(b) => Unexpected::Bool(b), + Content::U8(n) => Unexpected::Unsigned(n as u64), + Content::U16(n) => Unexpected::Unsigned(n as u64), + Content::U32(n) => Unexpected::Unsigned(n as u64), + Content::U64(n) => Unexpected::Unsigned(n), + Content::I8(n) => Unexpected::Signed(n as i64), + Content::I16(n) => Unexpected::Signed(n as i64), + Content::I32(n) => Unexpected::Signed(n as i64), + Content::I64(n) => Unexpected::Signed(n), + Content::F32(f) => Unexpected::Float(f as f64), + Content::F64(f) => Unexpected::Float(f), + Content::Char(c) => Unexpected::Char(c), + Content::String(ref s) => Unexpected::Str(s), + Content::Str(s) => Unexpected::Str(s), + Content::ByteBuf(ref b) => Unexpected::Bytes(b), + Content::Bytes(b) => Unexpected::Bytes(b), + Content::None | Content::Some(_) => Unexpected::Option, + Content::Unit => Unexpected::Unit, + Content::Newtype(_) => Unexpected::NewtypeStruct, + Content::Seq(_) => Unexpected::Seq, + Content::Map(_) => Unexpected::Map, + } + } + + pub struct ContentVisitor<'de> { value: PhantomData>, } impl<'de> ContentVisitor<'de> { - fn new() -> Self { + pub fn new() -> Self { ContentVisitor { value: PhantomData } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de> DeserializeSeed<'de> for ContentVisitor<'de> { + type Value = Content<'de>; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.__deserialize_content_v1(self) + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> Visitor<'de> for ContentVisitor<'de> { type Value = Content<'de>; @@ -479,22 +461,25 @@ mod content { where D: Deserializer<'de>, { - Deserialize::deserialize(deserializer).map(|v| Content::Some(Box::new(v))) + let v = tri!(ContentVisitor::new().deserialize(deserializer)); + Ok(Content::Some(Box::new(v))) } fn visit_newtype_struct(self, deserializer: D) -> Result where D: Deserializer<'de>, { - Deserialize::deserialize(deserializer).map(|v| Content::Newtype(Box::new(v))) + let v = tri!(ContentVisitor::new().deserialize(deserializer)); + Ok(Content::Newtype(Box::new(v))) } fn visit_seq(self, mut visitor: V) -> Result where V: SeqAccess<'de>, { - let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); - while let Some(e) = try!(visitor.next_element()) { + let mut vec = + Vec::::with_capacity(size_hint::cautious::(visitor.size_hint())); + while let Some(e) = tri!(visitor.next_element_seed(ContentVisitor::new())) { vec.push(e); } Ok(Content::Seq(vec)) @@ -504,8 +489,13 @@ mod content { where V: MapAccess<'de>, { - let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); - while let Some(kv) = try!(visitor.next_entry()) { + let mut vec = + Vec::<(Content, Content)>::with_capacity( + size_hint::cautious::<(Content, Content)>(visitor.size_hint()), + ); + while let Some(kv) = + tri!(visitor.next_entry_seed(ContentVisitor::new(), ContentVisitor::new())) + { vec.push(kv); } Ok(Content::Map(vec)) @@ -529,6 +519,8 @@ mod content { Content(Content<'de>), } + /// Serves as a seed for deserializing a key of internally tagged enum. + /// Cannot capture externally tagged enums, `i128` and `u128`. struct TagOrContentVisitor<'de> { name: &'static str, value: PhantomData>, @@ -537,12 +529,13 @@ mod content { impl<'de> TagOrContentVisitor<'de> { fn new(name: &'static str) -> Self { TagOrContentVisitor { - name: name, + name, value: PhantomData, } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> DeserializeSeed<'de> for TagOrContentVisitor<'de> { type Value = TagOrContent<'de>; @@ -556,6 +549,7 @@ mod content { } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> Visitor<'de> for TagOrContentVisitor<'de> { type Value = TagOrContent<'de>; @@ -815,70 +809,51 @@ mod content { /// Used by generated code to deserialize an internally tagged enum. /// + /// Captures map or sequence from the original deserializer and searches + /// a tag in it (in case of sequence, tag is the first element of sequence). + /// /// Not public API. - pub struct TaggedContent<'de, T> { - pub tag: T, - pub content: Content<'de>, - } - - /// Not public API. - pub struct TaggedContentVisitor<'de, T> { + pub struct TaggedContentVisitor { tag_name: &'static str, - value: PhantomData>, + expecting: &'static str, + value: PhantomData, } - impl<'de, T> TaggedContentVisitor<'de, T> { + impl TaggedContentVisitor { /// Visitor for the content of an internally tagged enum with the given /// tag name. - pub fn new(name: &'static str) -> Self { + pub fn new(name: &'static str, expecting: &'static str) -> Self { TaggedContentVisitor { tag_name: name, + expecting, value: PhantomData, } } } - impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<'de, T> - where - T: Deserialize<'de>, - { - type Value = TaggedContent<'de, T>; - - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // Internally tagged enums are only supported in self-describing - // formats. - deserializer.deserialize_any(self) - } - } - - impl<'de, T> Visitor<'de> for TaggedContentVisitor<'de, T> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, T> Visitor<'de> for TaggedContentVisitor where T: Deserialize<'de>, { - type Value = TaggedContent<'de, T>; + type Value = (T, Content<'de>); fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str("internally tagged enum") + fmt.write_str(self.expecting) } fn visit_seq(self, mut seq: S) -> Result where S: SeqAccess<'de>, { - let tag = match try!(seq.next_element()) { + let tag = match tri!(seq.next_element()) { Some(tag) => tag, None => { return Err(de::Error::missing_field(self.tag_name)); } }; let rest = de::value::SeqAccessDeserializer::new(seq); - Ok(TaggedContent { - tag: tag, - content: try!(Content::deserialize(rest)), - }) + Ok((tag, tri!(ContentVisitor::new().deserialize(rest)))) } fn visit_map(self, mut map: M) -> Result @@ -886,27 +861,27 @@ mod content { M: MapAccess<'de>, { let mut tag = None; - let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint())); - while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) { + let mut vec = Vec::<(Content, Content)>::with_capacity(size_hint::cautious::<( + Content, + Content, + )>(map.size_hint())); + while let Some(k) = tri!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) { match k { TagOrContent::Tag => { if tag.is_some() { return Err(de::Error::duplicate_field(self.tag_name)); } - tag = Some(try!(map.next_value())); + tag = Some(tri!(map.next_value())); } TagOrContent::Content(k) => { - let v = try!(map.next_value()); + let v = tri!(map.next_value_seed(ContentVisitor::new())); vec.push((k, v)); } } } match tag { None => Err(de::Error::missing_field(self.tag_name)), - Some(tag) => Ok(TaggedContent { - tag: tag, - content: Content::Map(vec), - }), + Some(tag) => Ok((tag, Content::Map(vec))), } } } @@ -921,10 +896,13 @@ mod content { /// Not public API. pub struct TagOrContentFieldVisitor { + /// Name of the tag field of the adjacently tagged enum pub tag: &'static str, + /// Name of the content field of the adjacently tagged enum pub content: &'static str, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> DeserializeSeed<'de> for TagOrContentFieldVisitor { type Value = TagOrContentField; @@ -932,10 +910,11 @@ mod content { where D: Deserializer<'de>, { - deserializer.deserialize_str(self) + deserializer.deserialize_identifier(self) } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> Visitor<'de> for TagOrContentFieldVisitor { type Value = TagOrContentField; @@ -943,6 +922,20 @@ mod content { write!(formatter, "{:?} or {:?}", self.tag, self.content) } + fn visit_u64(self, field_index: u64) -> Result + where + E: de::Error, + { + match field_index { + 0 => Ok(TagOrContentField::Tag), + 1 => Ok(TagOrContentField::Content), + _ => Err(de::Error::invalid_value( + Unexpected::Unsigned(field_index), + &self, + )), + } + } + fn visit_str(self, field: &str) -> Result where E: de::Error, @@ -955,6 +948,19 @@ mod content { Err(de::Error::invalid_value(Unexpected::Str(field), &self)) } } + + fn visit_bytes(self, field: &[u8]) -> Result + where + E: de::Error, + { + if field == self.tag.as_bytes() { + Ok(TagOrContentField::Tag) + } else if field == self.content.as_bytes() { + Ok(TagOrContentField::Content) + } else { + Err(de::Error::invalid_value(Unexpected::Bytes(field), &self)) + } + } } /// Used by generated code to deserialize an adjacently tagged enum when @@ -969,10 +975,13 @@ mod content { /// Not public API. pub struct TagContentOtherFieldVisitor { + /// Name of the tag field of the adjacently tagged enum pub tag: &'static str, + /// Name of the content field of the adjacently tagged enum pub content: &'static str, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> DeserializeSeed<'de> for TagContentOtherFieldVisitor { type Value = TagContentOtherField; @@ -980,10 +989,11 @@ mod content { where D: Deserializer<'de>, { - deserializer.deserialize_str(self) + deserializer.deserialize_identifier(self) } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de> Visitor<'de> for TagContentOtherFieldVisitor { type Value = TagContentOtherField; @@ -995,13 +1005,31 @@ mod content { ) } + fn visit_u64(self, field_index: u64) -> Result + where + E: de::Error, + { + match field_index { + 0 => Ok(TagContentOtherField::Tag), + 1 => Ok(TagContentOtherField::Content), + _ => Ok(TagContentOtherField::Other), + } + } + fn visit_str(self, field: &str) -> Result where E: de::Error, { - if field == self.tag { + self.visit_bytes(field.as_bytes()) + } + + fn visit_bytes(self, field: &[u8]) -> Result + where + E: de::Error, + { + if field == self.tag.as_bytes() { Ok(TagContentOtherField::Tag) - } else if field == self.content { + } else if field == self.content.as_bytes() { Ok(TagContentOtherField::Content) } else { Ok(TagContentOtherField::Other) @@ -1020,8 +1048,8 @@ mod content { E: de::Error, { #[cold] - fn invalid_type(self, exp: &Expected) -> E { - de::Error::invalid_type(self.content.unexpected(), exp) + fn invalid_type(self, exp: &dyn Expected) -> E { + de::Error::invalid_type(content_unexpected(&self.content), exp) } fn deserialize_integer(self, visitor: V) -> Result @@ -1040,6 +1068,25 @@ mod content { _ => Err(self.invalid_type(&visitor)), } } + + fn deserialize_float(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } } fn visit_content_seq<'de, V, E>(content: Vec>, visitor: V) -> Result @@ -1047,10 +1094,9 @@ mod content { V: Visitor<'de>, E: de::Error, { - let seq = content.into_iter().map(ContentDeserializer::new); - let mut seq_visitor = de::value::SeqDeserializer::new(seq); - let value = try!(visitor.visit_seq(&mut seq_visitor)); - try!(seq_visitor.end()); + let mut seq_visitor = SeqDeserializer::new(content); + let value = tri!(visitor.visit_seq(&mut seq_visitor)); + tri!(seq_visitor.end()); Ok(value) } @@ -1062,17 +1108,15 @@ mod content { V: Visitor<'de>, E: de::Error, { - let map = content - .into_iter() - .map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v))); - let mut map_visitor = de::value::MapDeserializer::new(map); - let value = try!(visitor.visit_map(&mut map_visitor)); - try!(map_visitor.end()); + let mut map_visitor = MapDeserializer::new(content); + let value = tri!(visitor.visit_map(&mut map_visitor)); + tri!(map_visitor.end()); Ok(value) } /// Used when deserializing an internally tagged enum because the content /// will be used exactly once. + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E> where E: de::Error, @@ -1179,25 +1223,14 @@ mod content { where V: Visitor<'de>, { - match self.content { - Content::F32(v) => visitor.visit_f32(v), - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { - match self.content { - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_char(self, visitor: V) -> Result @@ -1271,6 +1304,17 @@ mod content { { match self.content { Content::Unit => visitor.visit_unit(), + + // Allow deserializing newtype variant containing unit. + // + // #[derive(Deserialize)] + // #[serde(tag = "result")] + // enum Response { + // Success(T), + // } + // + // We want {"result":"Success"} to deserialize into Response<()>. + Content::Map(ref v) if v.is_empty() => visitor.visit_unit(), _ => Err(self.invalid_type(&visitor)), } } @@ -1297,8 +1341,9 @@ mod content { // } // // We want {"topic":"Info"} to deserialize even though - // ordinarily unit structs do not deserialize from empty map. + // ordinarily unit structs do not deserialize from empty map/seq. Content::Map(ref v) if v.is_empty() => visitor.visit_unit(), + Content::Seq(ref v) if v.is_empty() => visitor.visit_unit(), _ => self.deserialize_any(visitor), } } @@ -1405,7 +1450,7 @@ mod content { s @ Content::String(_) | s @ Content::Str(_) => (s, None), other => { return Err(de::Error::invalid_type( - other.unexpected(), + content_unexpected(&other), &"string or map", )); } @@ -1436,193 +1481,268 @@ mod content { drop(self); visitor.visit_unit() } + + fn __deserialize_content_v1(self, visitor: V) -> Result + where + V: Visitor<'de, Value = Content<'de>>, + { + let _ = visitor; + Ok(self.content) + } } impl<'de, E> ContentDeserializer<'de, E> { /// private API, don't use pub fn new(content: Content<'de>) -> Self { ContentDeserializer { - content: content, + content, err: PhantomData, } } } - pub struct EnumDeserializer<'de, E> - where - E: de::Error, - { - variant: Content<'de>, - value: Option>, - err: PhantomData, + struct SeqDeserializer<'de, E> { + iter: > as IntoIterator>::IntoIter, + count: usize, + marker: PhantomData, } - impl<'de, E> EnumDeserializer<'de, E> + impl<'de, E> SeqDeserializer<'de, E> { + fn new(content: Vec>) -> Self { + SeqDeserializer { + iter: content.into_iter(), + count: 0, + marker: PhantomData, + } + } + } + + impl<'de, E> SeqDeserializer<'de, E> where E: de::Error, { - pub fn new(variant: Content<'de>, value: Option>) -> EnumDeserializer<'de, E> { - EnumDeserializer { - variant: variant, - value: value, - err: PhantomData, + fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInSeq(self.count), + )) } } } - impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> Deserializer<'de> for SeqDeserializer<'de, E> where E: de::Error, { type Error = E; - type Variant = VariantDeserializer<'de, Self::Error>; - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), E> + fn deserialize_any(mut self, visitor: V) -> Result where - V: de::DeserializeSeed<'de>, + V: Visitor<'de>, { - let visitor = VariantDeserializer { - value: self.value, - err: PhantomData, - }; - seed.deserialize(ContentDeserializer::new(self.variant)) - .map(|v| (v, visitor)) + let v = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(v) } - } - pub struct VariantDeserializer<'de, E> - where - E: de::Error, - { - value: Option>, - err: PhantomData, + serde_core::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, E> de::VariantAccess<'de> for VariantDeserializer<'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> SeqAccess<'de> for SeqDeserializer<'de, E> where E: de::Error, { type Error = E; - fn unit_variant(self) -> Result<(), E> { - match self.value { - Some(value) => de::Deserialize::deserialize(ContentDeserializer::new(value)), - None => Ok(()), - } - } - - fn newtype_variant_seed(self, seed: T) -> Result + fn next_element_seed(&mut self, seed: V) -> Result, Self::Error> where - T: de::DeserializeSeed<'de>, + V: DeserializeSeed<'de>, { - match self.value { - Some(value) => seed.deserialize(ContentDeserializer::new(value)), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"newtype variant", - )), + match self.iter.next() { + Some(value) => { + self.count += 1; + seed.deserialize(ContentDeserializer::new(value)).map(Some) + } + None => Ok(None), } } - fn tuple_variant(self, _len: usize, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - match self.value { - Some(Content::Seq(v)) => { - de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) - } - Some(other) => Err(de::Error::invalid_type( - other.unexpected(), - &"tuple variant", - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"tuple variant", - )), - } + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) } + } - fn struct_variant( - self, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - match self.value { - Some(Content::Map(v)) => { - de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) - } - Some(Content::Seq(v)) => { - de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) - } - Some(other) => Err(de::Error::invalid_type( - other.unexpected(), - &"struct variant", - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"struct variant", - )), + struct ExpectedInSeq(usize); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl Expected for ExpectedInSeq { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + formatter.write_str("1 element in sequence") + } else { + write!(formatter, "{} elements in sequence", self.0) } } } - struct SeqDeserializer<'de, E> - where - E: de::Error, - { - iter: > as IntoIterator>::IntoIter, - err: PhantomData, + struct MapDeserializer<'de, E> { + iter: , Content<'de>)> as IntoIterator>::IntoIter, + value: Option>, + count: usize, + error: PhantomData, } - impl<'de, E> SeqDeserializer<'de, E> - where - E: de::Error, - { - fn new(vec: Vec>) -> Self { - SeqDeserializer { - iter: vec.into_iter(), - err: PhantomData, + impl<'de, E> MapDeserializer<'de, E> { + fn new(content: Vec<(Content<'de>, Content<'de>)>) -> Self { + MapDeserializer { + iter: content.into_iter(), + value: None, + count: 0, + error: PhantomData, } } } - impl<'de, E> de::Deserializer<'de> for SeqDeserializer<'de, E> + impl<'de, E> MapDeserializer<'de, E> where E: de::Error, { - type Error = E; - - #[inline] - fn deserialize_any(mut self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - let len = self.iter.len(); - if len == 0 { - visitor.visit_unit() + fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) } else { - let ret = try!(visitor.visit_seq(&mut self)); - let remaining = self.iter.len(); - if remaining == 0 { - Ok(ret) - } else { - Err(de::Error::invalid_length(len, &"fewer elements in array")) + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInMap(self.count), + )) + } + } + } + + impl<'de, E> MapDeserializer<'de, E> { + fn next_pair(&mut self) -> Option<(Content<'de>, Content<'de>)> { + match self.iter.next() { + Some((k, v)) => { + self.count += 1; + Some((k, v)) } + None => None, } } + } - forward_to_deserialize_any! { + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> Deserializer<'de> for MapDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let value = tri!(visitor.visit_map(&mut self)); + tri!(self.end()); + Ok(value) + } + + fn deserialize_seq(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let value = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(value) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let _ = len; + self.deserialize_seq(visitor) + } + + serde_core::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 + bytes byte_buf option unit unit_struct newtype_struct tuple_struct map + struct enum identifier ignored_any + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> MapAccess<'de> for MapDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(ContentDeserializer::new(key)).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + let value = self.value.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let value = value.expect("MapAccess::next_value called before next_key"); + seed.deserialize(ContentDeserializer::new(value)) + } + + fn next_entry_seed( + &mut self, + kseed: TK, + vseed: TV, + ) -> Result, Self::Error> + where + TK: DeserializeSeed<'de>, + TV: DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + let key = tri!(kseed.deserialize(ContentDeserializer::new(key))); + let value = tri!(vseed.deserialize(ContentDeserializer::new(value))); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) } } - impl<'de, E> de::SeqAccess<'de> for SeqDeserializer<'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> SeqAccess<'de> for MapDeserializer<'de, E> where E: de::Error, { @@ -1632,8 +1752,11 @@ mod content { where T: de::DeserializeSeed<'de>, { - match self.iter.next() { - Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some), + match self.next_pair() { + Some((k, v)) => { + let de = PairDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } None => Ok(None), } } @@ -1643,80 +1766,225 @@ mod content { } } - struct MapDeserializer<'de, E> + struct PairDeserializer<'de, E>(Content<'de>, Content<'de>, PhantomData); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> Deserializer<'de> for PairDeserializer<'de, E> where E: de::Error, { - iter: , Content<'de>)> as IntoIterator>::IntoIter, + type Error = E; + + serde_core::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 tuple_struct map + struct enum identifier ignored_any + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut pair_visitor = PairVisitor(Some(self.0), Some(self.1), PhantomData); + let pair = tri!(visitor.visit_seq(&mut pair_visitor)); + if pair_visitor.1.is_none() { + Ok(pair) + } else { + let remaining = pair_visitor.size_hint().unwrap(); + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(2 - remaining))) + } + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + if len == 2 { + self.deserialize_seq(visitor) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(len))) + } + } + } + + struct PairVisitor<'de, E>(Option>, Option>, PhantomData); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> SeqAccess<'de> for PairVisitor<'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + if let Some(k) = self.0.take() { + seed.deserialize(ContentDeserializer::new(k)).map(Some) + } else if let Some(v) = self.1.take() { + seed.deserialize(ContentDeserializer::new(v)).map(Some) + } else { + Ok(None) + } + } + + fn size_hint(&self) -> Option { + if self.0.is_some() { + Some(2) + } else if self.1.is_some() { + Some(1) + } else { + Some(0) + } + } + } + + struct ExpectedInMap(usize); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl Expected for ExpectedInMap { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + formatter.write_str("1 element in map") + } else { + write!(formatter, "{} elements in map", self.0) + } + } + } + + pub struct EnumDeserializer<'de, E> + where + E: de::Error, + { + variant: Content<'de>, value: Option>, err: PhantomData, } - impl<'de, E> MapDeserializer<'de, E> + impl<'de, E> EnumDeserializer<'de, E> where E: de::Error, { - fn new(map: Vec<(Content<'de>, Content<'de>)>) -> Self { - MapDeserializer { - iter: map.into_iter(), - value: None, + pub fn new(variant: Content<'de>, value: Option>) -> EnumDeserializer<'de, E> { + EnumDeserializer { + variant, + value, err: PhantomData, } } } - impl<'de, E> de::MapAccess<'de> for MapDeserializer<'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E> where E: de::Error, { type Error = E; + type Variant = VariantDeserializer<'de, Self::Error>; - fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), E> where - T: de::DeserializeSeed<'de>, + V: de::DeserializeSeed<'de>, { - match self.iter.next() { - Some((key, value)) => { - self.value = Some(value); - seed.deserialize(ContentDeserializer::new(key)).map(Some) - } - None => Ok(None), + let visitor = VariantDeserializer { + value: self.value, + err: PhantomData, + }; + seed.deserialize(ContentDeserializer::new(self.variant)) + .map(|v| (v, visitor)) + } + } + + pub struct VariantDeserializer<'de, E> + where + E: de::Error, + { + value: Option>, + err: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> de::VariantAccess<'de> for VariantDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), E> { + match self.value { + Some(value) => de::Deserialize::deserialize(ContentDeserializer::new(value)), + None => Ok(()), } } - fn next_value_seed(&mut self, seed: T) -> Result + fn newtype_variant_seed(self, seed: T) -> Result where T: de::DeserializeSeed<'de>, { - match self.value.take() { + match self.value { Some(value) => seed.deserialize(ContentDeserializer::new(value)), - None => Err(de::Error::custom("value is missing")), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), } } - fn size_hint(&self) -> Option { - size_hint::from_bounds(&self.iter) - } - } - - impl<'de, E> de::Deserializer<'de> for MapDeserializer<'de, E> - where - E: de::Error, - { - type Error = E; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result + fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { - visitor.visit_map(self) + match self.value { + Some(Content::Seq(v)) => { + de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + content_unexpected(&other), + &"tuple variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } } - 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 + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self.value { + Some(Content::Map(v)) => { + de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + } + Some(Content::Seq(v)) => { + de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + content_unexpected(&other), + &"struct variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } } } @@ -1731,8 +1999,8 @@ mod content { E: de::Error, { #[cold] - fn invalid_type(self, exp: &Expected) -> E { - de::Error::invalid_type(self.content.unexpected(), exp) + fn invalid_type(self, exp: &dyn Expected) -> E { + de::Error::invalid_type(content_unexpected(self.content), exp) } fn deserialize_integer(self, visitor: V) -> Result @@ -1751,6 +2019,25 @@ mod content { _ => Err(self.invalid_type(&visitor)), } } + + fn deserialize_float(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } } fn visit_content_seq_ref<'a, 'de, V, E>( @@ -1761,10 +2048,9 @@ mod content { V: Visitor<'de>, E: de::Error, { - let seq = content.iter().map(ContentRefDeserializer::new); - let mut seq_visitor = de::value::SeqDeserializer::new(seq); - let value = try!(visitor.visit_seq(&mut seq_visitor)); - try!(seq_visitor.end()); + let mut seq_visitor = SeqRefDeserializer::new(content); + let value = tri!(visitor.visit_seq(&mut seq_visitor)); + tri!(seq_visitor.end()); Ok(value) } @@ -1776,20 +2062,15 @@ mod content { V: Visitor<'de>, E: de::Error, { - let map = content.iter().map(|&(ref k, ref v)| { - ( - ContentRefDeserializer::new(k), - ContentRefDeserializer::new(v), - ) - }); - let mut map_visitor = de::value::MapDeserializer::new(map); - let value = try!(visitor.visit_map(&mut map_visitor)); - try!(map_visitor.end()); + let mut map_visitor = MapRefDeserializer::new(content); + let value = tri!(visitor.visit_map(&mut map_visitor)); + tri!(map_visitor.end()); Ok(value) } /// Used when deserializing an untagged enum because the content may need /// to be used more than once. + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E> where E: de::Error, @@ -1898,25 +2179,14 @@ mod content { where V: Visitor<'de>, { - match *self.content { - Content::F32(v) => visitor.visit_f32(v), - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { - match *self.content { - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_char(self, visitor: V) -> Result @@ -1976,10 +2246,19 @@ mod content { where V: Visitor<'de>, { + // Covered by tests/test_enum_untagged.rs + // with_optional_field::* match *self.content { Content::None => visitor.visit_none(), Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)), Content::Unit => visitor.visit_unit(), + // This case is to support data formats which do not encode an + // indication whether a value is optional. An example of such a + // format is JSON, and a counterexample is RON. When requesting + // `deserialize_any` in JSON, the data format never performs + // `Visitor::visit_some` but we still must be able to + // deserialize the resulting Content into data structures with + // optional fields. _ => visitor.visit_some(self), } } @@ -2009,10 +2288,21 @@ mod content { where V: Visitor<'de>, { + // Covered by tests/test_enum_untagged.rs + // newtype_struct match *self.content { Content::Newtype(ref v) => { visitor.visit_newtype_struct(ContentRefDeserializer::new(v)) } + // This case is to support data formats that encode newtype + // structs and their underlying data the same, with no + // indication whether a newtype wrapper was present. For example + // JSON does this, while RON does not. In RON a newtype's name + // is included in the serialized representation and it knows to + // call `Visitor::visit_newtype_struct` from `deserialize_any`. + // JSON's `deserialize_any` never calls `visit_newtype_struct` + // but in this code we still must be able to deserialize the + // resulting Content into newtypes. _ => visitor.visit_newtype_struct(self), } } @@ -2084,7 +2374,7 @@ mod content { let (variant, value) = match *self.content { Content::Map(ref value) => { let mut iter = value.iter(); - let &(ref variant, ref value) = match iter.next() { + let (variant, value) = match iter.next() { Some(v) => v, None => { return Err(de::Error::invalid_value( @@ -2105,15 +2395,15 @@ mod content { ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None), ref other => { return Err(de::Error::invalid_type( - other.unexpected(), + content_unexpected(other), &"string or map", )); } }; visitor.visit_enum(EnumRefDeserializer { - variant: variant, - value: value, + variant, + value, err: PhantomData, }) } @@ -2139,180 +2429,349 @@ mod content { { visitor.visit_unit() } + + fn __deserialize_content_v1(self, visitor: V) -> Result + where + V: Visitor<'de, Value = Content<'de>>, + { + let _ = visitor; + Ok(content_clone(self.content)) + } } impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> { /// private API, don't use pub fn new(content: &'a Content<'de>) -> Self { ContentRefDeserializer { - content: content, + content, err: PhantomData, } } } - struct EnumRefDeserializer<'a, 'de: 'a, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de: 'a, E> Copy for ContentRefDeserializer<'a, 'de, E> {} + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de: 'a, E> Clone for ContentRefDeserializer<'a, 'de, E> { + fn clone(&self) -> Self { + *self + } + } + + struct SeqRefDeserializer<'a, 'de, E> { + iter: <&'a [Content<'de>] as IntoIterator>::IntoIter, + count: usize, + marker: PhantomData, + } + + impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E> { + fn new(content: &'a [Content<'de>]) -> Self { + SeqRefDeserializer { + iter: content.iter(), + count: 0, + marker: PhantomData, + } + } + } + + impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E> where E: de::Error, { - variant: &'a Content<'de>, - value: Option<&'a Content<'de>>, - err: PhantomData, + fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInSeq(self.count), + )) + } + } } - impl<'de, 'a, E> de::EnumAccess<'de> for EnumRefDeserializer<'a, 'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> Deserializer<'de> for SeqRefDeserializer<'a, 'de, E> where E: de::Error, { type Error = E; - type Variant = VariantRefDeserializer<'a, 'de, Self::Error>; - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + fn deserialize_any(mut self, visitor: V) -> Result where - V: de::DeserializeSeed<'de>, + V: Visitor<'de>, { - let visitor = VariantRefDeserializer { - value: self.value, - err: PhantomData, - }; - seed.deserialize(ContentRefDeserializer::new(self.variant)) - .map(|v| (v, visitor)) + let v = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(v) + } + + serde_core::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 } } - struct VariantRefDeserializer<'a, 'de: 'a, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E> where E: de::Error, { + type Error = E; + + fn next_element_seed(&mut self, seed: V) -> Result, Self::Error> + where + V: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => { + self.count += 1; + seed.deserialize(ContentRefDeserializer::new(value)) + .map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } + } + + struct MapRefDeserializer<'a, 'de, E> { + iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter, value: Option<&'a Content<'de>>, - err: PhantomData, + count: usize, + error: PhantomData, } - impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E> + impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E> { + fn new(content: &'a [(Content<'de>, Content<'de>)]) -> Self { + MapRefDeserializer { + iter: content.iter(), + value: None, + count: 0, + error: PhantomData, + } + } + } + + impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E> where E: de::Error, { - type Error = E; + fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInMap(self.count), + )) + } + } + } - fn unit_variant(self) -> Result<(), E> { - match self.value { - Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)), - None => Ok(()), + impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E> { + fn next_pair(&mut self) -> Option<(&'a Content<'de>, &'a Content<'de>)> { + match self.iter.next() { + Some((k, v)) => { + self.count += 1; + Some((k, v)) + } + None => None, } } + } - fn newtype_variant_seed(self, seed: T) -> Result + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> Deserializer<'de> for MapRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result where - T: de::DeserializeSeed<'de>, + V: Visitor<'de>, { - match self.value { - Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"newtype variant", - )), - } + let value = tri!(visitor.visit_map(&mut self)); + tri!(self.end()); + Ok(value) } - fn tuple_variant(self, _len: usize, visitor: V) -> Result + fn deserialize_seq(mut self, visitor: V) -> Result where - V: de::Visitor<'de>, + V: Visitor<'de>, { - match self.value { - Some(&Content::Seq(ref v)) => { - de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + let value = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(value) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let _ = len; + self.deserialize_seq(visitor) + } + + serde_core::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 tuple_struct map + struct enum identifier ignored_any + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> MapAccess<'de> for MapRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(ContentRefDeserializer::new(key)).map(Some) } - Some(other) => Err(de::Error::invalid_type( - other.unexpected(), - &"tuple variant", - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"tuple variant", - )), + None => Ok(None), } } - fn struct_variant( - self, - _fields: &'static [&'static str], - visitor: V, - ) -> Result + fn next_value_seed(&mut self, seed: T) -> Result where - V: de::Visitor<'de>, + T: DeserializeSeed<'de>, { - match self.value { - Some(&Content::Map(ref v)) => { - de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor) - } - Some(&Content::Seq(ref v)) => { - de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + let value = self.value.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let value = value.expect("MapAccess::next_value called before next_key"); + seed.deserialize(ContentRefDeserializer::new(value)) + } + + fn next_entry_seed( + &mut self, + kseed: TK, + vseed: TV, + ) -> Result, Self::Error> + where + TK: DeserializeSeed<'de>, + TV: DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + let key = tri!(kseed.deserialize(ContentRefDeserializer::new(key))); + let value = tri!(vseed.deserialize(ContentRefDeserializer::new(value))); + Ok(Some((key, value))) } - Some(other) => Err(de::Error::invalid_type( - other.unexpected(), - &"struct variant", - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"struct variant", - )), + None => Ok(None), } } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } } - struct SeqRefDeserializer<'a, 'de: 'a, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> SeqAccess<'de> for MapRefDeserializer<'a, 'de, E> where E: de::Error, { - iter: <&'a [Content<'de>] as IntoIterator>::IntoIter, - err: PhantomData, + type Error = E; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((k, v)) => { + let de = PairRefDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } } - impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E> + struct PairRefDeserializer<'a, 'de, E>(&'a Content<'de>, &'a Content<'de>, PhantomData); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> Deserializer<'de> for PairRefDeserializer<'a, 'de, E> where E: de::Error, { - fn new(slice: &'a [Content<'de>]) -> Self { - SeqRefDeserializer { - iter: slice.iter(), - err: PhantomData, + type Error = E; + + serde_core::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 tuple_struct map + struct enum identifier ignored_any + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut pair_visitor = PairRefVisitor(Some(self.0), Some(self.1), PhantomData); + let pair = tri!(visitor.visit_seq(&mut pair_visitor)); + if pair_visitor.1.is_none() { + Ok(pair) + } else { + let remaining = pair_visitor.size_hint().unwrap(); + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(2 - remaining))) } } - } - - impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, 'de, E> - where - E: de::Error, - { - type Error = E; - #[inline] - fn deserialize_any(mut self, visitor: V) -> Result + fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { - let len = self.iter.len(); - if len == 0 { - visitor.visit_unit() + if len == 2 { + self.deserialize_seq(visitor) } else { - let ret = try!(visitor.visit_seq(&mut self)); - let remaining = self.iter.len(); - if remaining == 0 { - Ok(ret) - } else { - Err(de::Error::invalid_length(len, &"fewer elements in array")) - } + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(len))) } } - - 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, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E> + struct PairRefVisitor<'a, 'de, E>( + Option<&'a Content<'de>>, + Option<&'a Content<'de>>, + PhantomData, + ); + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a, 'de, E> SeqAccess<'de> for PairRefVisitor<'a, 'de, E> where E: de::Error, { @@ -2320,98 +2779,154 @@ mod content { fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where - T: de::DeserializeSeed<'de>, + T: DeserializeSeed<'de>, { - match self.iter.next() { - Some(value) => seed - .deserialize(ContentRefDeserializer::new(value)) - .map(Some), - None => Ok(None), + if let Some(k) = self.0.take() { + seed.deserialize(ContentRefDeserializer::new(k)).map(Some) + } else if let Some(v) = self.1.take() { + seed.deserialize(ContentRefDeserializer::new(v)).map(Some) + } else { + Ok(None) } } fn size_hint(&self) -> Option { - size_hint::from_bounds(&self.iter) + if self.0.is_some() { + Some(2) + } else if self.1.is_some() { + Some(1) + } else { + Some(0) + } } } - struct MapRefDeserializer<'a, 'de: 'a, E> + struct EnumRefDeserializer<'a, 'de: 'a, E> where E: de::Error, { - iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter, + variant: &'a Content<'de>, value: Option<&'a Content<'de>>, err: PhantomData, } - impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E> + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, 'a, E> de::EnumAccess<'de> for EnumRefDeserializer<'a, 'de, E> where E: de::Error, { - fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self { - MapRefDeserializer { - iter: map.iter(), - value: None, + type Error = E; + type Variant = VariantRefDeserializer<'a, 'de, Self::Error>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let visitor = VariantRefDeserializer { + value: self.value, err: PhantomData, - } + }; + seed.deserialize(ContentRefDeserializer::new(self.variant)) + .map(|v| (v, visitor)) } } - impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, 'de, E> + struct VariantRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + value: Option<&'a Content<'de>>, + err: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E> where E: de::Error, { type Error = E; - fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some(&(ref key, ref value)) => { - self.value = Some(value); - seed.deserialize(ContentRefDeserializer::new(key)).map(Some) - } - None => Ok(None), + fn unit_variant(self) -> Result<(), E> { + match self.value { + Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)), + // Covered by tests/test_annotations.rs + // test_partially_untagged_adjacently_tagged_enum + // Covered by tests/test_enum_untagged.rs + // newtype_enum::unit + None => Ok(()), } } - fn next_value_seed(&mut self, seed: T) -> Result + fn newtype_variant_seed(self, seed: T) -> Result where T: de::DeserializeSeed<'de>, { - match self.value.take() { + match self.value { + // Covered by tests/test_annotations.rs + // test_partially_untagged_enum_desugared + // test_partially_untagged_enum_generic + // Covered by tests/test_enum_untagged.rs + // newtype_enum::newtype Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), - None => Err(de::Error::custom("value is missing")), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), } } - fn size_hint(&self) -> Option { - size_hint::from_bounds(&self.iter) - } - } - - impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, 'de, E> - where - E: de::Error, - { - type Error = E; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result + fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { - visitor.visit_map(self) + match self.value { + // Covered by tests/test_annotations.rs + // test_partially_untagged_enum + // test_partially_untagged_enum_desugared + // Covered by tests/test_enum_untagged.rs + // newtype_enum::tuple0 + // newtype_enum::tuple2 + Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor), + Some(other) => Err(de::Error::invalid_type( + content_unexpected(other), + &"tuple variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } } - 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 + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self.value { + // Covered by tests/test_enum_untagged.rs + // newtype_enum::struct_from_map + Some(Content::Map(v)) => visit_content_map_ref(v, visitor), + // Covered by tests/test_enum_untagged.rs + // newtype_enum::struct_from_seq + // newtype_enum::empty_struct_from_seq + Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor), + Some(other) => Err(de::Error::invalid_type( + content_unexpected(other), + &"struct variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E> where E: de::Error, @@ -2423,6 +2938,7 @@ mod content { } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E> where E: de::Error, @@ -2446,12 +2962,13 @@ mod content { /// Not public API. pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { InternallyTaggedUnitVisitor { - type_name: type_name, - variant_name: variant_name, + type_name, + variant_name, } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> { type Value = (); @@ -2474,7 +2991,7 @@ mod content { where M: MapAccess<'de>, { - while try!(access.next_entry::()).is_some() {} + while tri!(access.next_entry::()).is_some() {} Ok(()) } } @@ -2491,12 +3008,13 @@ mod content { /// Not public API. pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { UntaggedUnitVisitor { - type_name: type_name, - variant_name: variant_name, + type_name, + variant_name, } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> { type Value = (); @@ -2542,11 +3060,14 @@ pub trait IdentifierDeserializer<'de, E: Error> { fn from(self) -> Self::Deserializer; } -impl<'de, E> IdentifierDeserializer<'de, E> for u32 +pub struct Borrowed<'de, T: 'de + ?Sized>(pub &'de T); + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> IdentifierDeserializer<'de, E> for u64 where E: Error, { - type Deserializer = >::Deserializer; + type Deserializer = >::Deserializer; fn from(self) -> Self::Deserializer { self.into_deserializer() @@ -2558,21 +3079,34 @@ pub struct StrDeserializer<'a, E> { marker: PhantomData, } -impl<'a, E> IdentifierDeserializer<'a, E> for &'a str +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E> where E: Error, { - type Deserializer = StrDeserializer<'a, E>; + type Error = E; - fn from(self) -> Self::Deserializer { - StrDeserializer { - value: self, - marker: PhantomData, - } + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_str(self.value) + } + + serde_core::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, 'a, E> Deserializer<'de> for StrDeserializer<'a, E> +pub struct BorrowedStrDeserializer<'de, E> { + value: &'de str, + marker: PhantomData, +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> Deserializer<'de> for BorrowedStrDeserializer<'de, E> where E: Error, { @@ -2582,70 +3116,67 @@ where where V: Visitor<'de>, { - visitor.visit_str(self.value) + visitor.visit_borrowed_str(self.value) } - forward_to_deserialize_any! { + serde_core::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 } } -pub struct BytesDeserializer<'a, E> { - value: &'a [u8], - marker: PhantomData, -} - -impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, E> IdentifierDeserializer<'a, E> for &'a str where E: Error, { - type Deserializer = BytesDeserializer<'a, E>; + type Deserializer = StrDeserializer<'a, E>; fn from(self) -> Self::Deserializer { - BytesDeserializer { + StrDeserializer { value: self, marker: PhantomData, } } } -impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E> +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, str> where E: Error, { - type Error = E; + type Deserializer = BorrowedStrDeserializer<'de, E>; - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_bytes(self.value) + fn from(self) -> Self::Deserializer { + BorrowedStrDeserializer { + value: self.0, + marker: PhantomData, + } } +} - 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 +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] +where + E: Error, +{ + type Deserializer = BytesDeserializer<'a, E>; + + fn from(self) -> Self::Deserializer { + BytesDeserializer::new(self) } } -/// A DeserializeSeed helper for implementing deserialize_in_place Visitors. -/// -/// Wraps a mutable reference and calls deserialize_in_place on it. -pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T); - -impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T> +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, [u8]> where - T: Deserialize<'de>, + E: Error, { - type Value = (); - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - T::deserialize_in_place(deserializer, self.0) + type Deserializer = BorrowedBytesDeserializer<'de, E>; + + fn from(self) -> Self::Deserializer { + BorrowedBytesDeserializer::new(self.0) } } @@ -2667,7 +3198,7 @@ where #[cfg(any(feature = "std", feature = "alloc"))] macro_rules! forward_to_deserialize_other { - ($($func:ident ( $($arg:ty),* ))*) => { + ($($func:ident ($($arg:ty),*))*) => { $( fn $func(self, $(_: $arg,)* _visitor: V) -> Result where @@ -2680,6 +3211,7 @@ macro_rules! forward_to_deserialize_other { } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E> where E: Error, @@ -2690,11 +3222,7 @@ where where V: Visitor<'de>, { - visitor.visit_map(FlatInternallyTaggedAccess { - iter: self.0.iter_mut(), - pending: None, - _marker: PhantomData, - }) + self.deserialize_map(visitor) } fn deserialize_enum( @@ -2706,17 +3234,8 @@ where where V: Visitor<'de>, { - for item in self.0.iter_mut() { - // items in the vector are nulled out when used. So we can only use - // an item if it's still filled in and if the field is one we care - // about. - let use_item = match *item { - None => false, - Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)), - }; - - if use_item { - let (key, value) = item.take().unwrap(); + for entry in self.0 { + if let Some((key, value)) = flat_map_take_entry(entry, variants) { return visitor.visit_enum(EnumDeserializer::new(key, Some(value))); } } @@ -2731,7 +3250,11 @@ where where V: Visitor<'de>, { - visitor.visit_map(FlatMapAccess::new(self.0.iter())) + visitor.visit_map(FlatMapAccess { + iter: self.0.iter(), + pending_content: None, + _marker: PhantomData, + }) } fn deserialize_struct( @@ -2743,7 +3266,12 @@ where where V: Visitor<'de>, { - visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields)) + visitor.visit_map(FlatStructAccess { + iter: self.0.iter_mut(), + pending_content: None, + fields, + _marker: PhantomData, + }) } fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result @@ -2770,6 +3298,24 @@ where visitor.visit_unit() } + fn deserialize_unit_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + forward_to_deserialize_other! { deserialize_bool() deserialize_i8() @@ -2787,36 +3333,22 @@ where deserialize_string() deserialize_bytes() deserialize_byte_buf() - deserialize_unit_struct(&'static str) deserialize_seq() deserialize_tuple(usize) deserialize_tuple_struct(&'static str, usize) deserialize_identifier() - deserialize_ignored_any() } } #[cfg(any(feature = "std", feature = "alloc"))] -pub struct FlatMapAccess<'a, 'de: 'a, E> { +struct FlatMapAccess<'a, 'de: 'a, E> { iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, pending_content: Option<&'a Content<'de>>, _marker: PhantomData, } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> { - fn new( - iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, - ) -> FlatMapAccess<'a, 'de, E> { - FlatMapAccess { - iter: iter, - pending_content: None, - _marker: PhantomData, - } - } -} - -#[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> where E: Error, @@ -2827,9 +3359,13 @@ where where T: DeserializeSeed<'de>, { - while let Some(item) = self.iter.next() { + for item in &mut self.iter { // Items in the vector are nulled out when used by a struct. if let Some((ref key, ref content)) = *item { + // Do not take(), instead borrow this entry. The internally tagged + // enum does its own buffering so we can't tell whether this entry + // is going to be consumed. Borrowing here leaves the entry + // available for later flattened fields. self.pending_content = Some(content); return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); } @@ -2849,7 +3385,7 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -pub struct FlatStructAccess<'a, 'de: 'a, E> { +struct FlatStructAccess<'a, 'de: 'a, E> { iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, pending_content: Option>, fields: &'static [&'static str], @@ -2857,21 +3393,7 @@ pub struct FlatStructAccess<'a, 'de: 'a, E> { } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> { - fn new( - iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, - fields: &'static [&'static str], - ) -> FlatStructAccess<'a, 'de, E> { - FlatStructAccess { - iter: iter, - pending_content: None, - fields: fields, - _marker: PhantomData, - } - } -} - -#[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E> where E: Error, @@ -2882,17 +3404,8 @@ where where T: DeserializeSeed<'de>, { - while let Some(item) = self.iter.next() { - // items in the vector are nulled out when used. So we can only use - // an item if it's still filled in and if the field is one we care - // about. In case we do not know which fields we want, we take them all. - let use_item = match *item { - None => false, - Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)), - }; - - if use_item { - let (key, content) = item.take().unwrap(); + for entry in self.iter.by_ref() { + if let Some((key, content)) = flat_map_take_entry(entry, self.fields) { self.pending_content = Some(content); return seed.deserialize(ContentDeserializer::new(key)).map(Some); } @@ -2911,44 +3424,78 @@ where } } +/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the +/// field name matches any of the recognized ones. #[cfg(any(feature = "std", feature = "alloc"))] -pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> { - iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, - pending: Option<&'a Content<'de>>, - _marker: PhantomData, +fn flat_map_take_entry<'de>( + entry: &mut Option<(Content<'de>, Content<'de>)>, + recognized: &[&str], +) -> Option<(Content<'de>, Content<'de>)> { + // Entries in the FlatMapDeserializer buffer are nulled out as they get + // claimed for deserialization. We only use an entry if it is still present + // and if the field is one recognized by the current data structure. + let is_recognized = match entry { + None => false, + Some((k, _v)) => content_as_str(k).map_or(false, |name| recognized.contains(&name)), + }; + + if is_recognized { + entry.take() + } else { + None + } } -#[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E> +pub struct AdjacentlyTaggedEnumVariantSeed { + pub enum_name: &'static str, + pub variants: &'static [&'static str], + pub fields_enum: PhantomData, +} + +pub struct AdjacentlyTaggedEnumVariantVisitor { + enum_name: &'static str, + fields_enum: PhantomData, +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, F> Visitor<'de> for AdjacentlyTaggedEnumVariantVisitor where - E: Error, + F: Deserialize<'de>, { - type Error = E; + type Value = F; - fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "variant of enum {}", self.enum_name) + } + + fn visit_enum(self, data: A) -> Result where - T: DeserializeSeed<'de>, + A: EnumAccess<'de>, { - while let Some(item) = self.iter.next() { - if let Some((ref key, ref content)) = *item { - // Do not take(), instead borrow this entry. The internally tagged - // enum does its own buffering so we can't tell whether this entry - // is going to be consumed. Borrowing here leaves the entry - // available for later flattened fields. - self.pending = Some(content); - return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); - } - } - Ok(None) + let (variant, variant_access) = tri!(data.variant()); + tri!(variant_access.unit_variant()); + Ok(variant) } +} - fn next_value_seed(&mut self, seed: T) -> Result +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, F> DeserializeSeed<'de> for AdjacentlyTaggedEnumVariantSeed +where + F: Deserialize<'de>, +{ + type Value = F; + + fn deserialize(self, deserializer: D) -> Result where - T: DeserializeSeed<'de>, + D: Deserializer<'de>, { - match self.pending.take() { - Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), - None => panic!("value is missing"), - } + deserializer.deserialize_enum( + self.enum_name, + self.variants, + AdjacentlyTaggedEnumVariantVisitor { + enum_name: self.enum_name, + fields_enum: PhantomData, + }, + ) } } diff --git a/serde/src/private/mod.rs b/serde/src/private/mod.rs index 79e0a7d00..20bfa4eb8 100644 --- a/serde/src/private/mod.rs +++ b/serde/src/private/mod.rs @@ -1,4 +1,18 @@ -mod macros; - +#[cfg(not(no_serde_derive))] pub mod de; +#[cfg(not(no_serde_derive))] pub mod ser; + +pub use crate::lib::clone::Clone; +pub use crate::lib::convert::{From, Into, TryFrom}; +pub use crate::lib::default::Default; +pub use crate::lib::fmt::{self, Formatter}; +pub use crate::lib::marker::PhantomData; +pub use crate::lib::option::Option::{self, None, Some}; +pub use crate::lib::ptr; +pub use crate::lib::result::Result::{self, Err, Ok}; + +pub use crate::serde_core_private::string::from_utf8_lossy; + +#[cfg(any(feature = "alloc", feature = "std"))] +pub use crate::lib::{ToString, Vec}; diff --git a/serde/src/private/ser.rs b/serde/src/private/ser.rs index eb8cfc988..411e2b41e 100644 --- a/serde/src/private/ser.rs +++ b/serde/src/private/ser.rs @@ -1,6 +1,6 @@ -use lib::*; +use crate::lib::*; -use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; +use crate::ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; #[cfg(any(feature = "std", feature = "alloc"))] use self::content::{ @@ -27,10 +27,10 @@ where T: Serialize, { value.serialize(TaggedSerializer { - type_ident: type_ident, - variant_ident: variant_ident, - tag: tag, - variant_name: variant_name, + type_ident, + variant_ident, + tag, + variant_name, delegate: serializer, }) } @@ -51,15 +51,14 @@ enum Unsupported { String, ByteArray, Optional, - Unit, - #[cfg(any(feature = "std", feature = "alloc"))] - UnitStruct, Sequence, Tuple, TupleStruct, + #[cfg(not(any(feature = "std", feature = "alloc")))] Enum, } +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl Display for Unsupported { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -70,12 +69,10 @@ impl Display for Unsupported { Unsupported::String => formatter.write_str("a string"), Unsupported::ByteArray => formatter.write_str("a byte array"), Unsupported::Optional => formatter.write_str("an optional"), - Unsupported::Unit => formatter.write_str("unit"), - #[cfg(any(feature = "std", feature = "alloc"))] - Unsupported::UnitStruct => formatter.write_str("unit struct"), Unsupported::Sequence => formatter.write_str("a sequence"), Unsupported::Tuple => formatter.write_str("a tuple"), Unsupported::TupleStruct => formatter.write_str("a tuple struct"), + #[cfg(not(any(feature = "std", feature = "alloc")))] Unsupported::Enum => formatter.write_str("an enum"), } } @@ -93,6 +90,7 @@ where } } +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl Serializer for TaggedSerializer where S: Serializer, @@ -176,20 +174,22 @@ where Err(self.bad_type(Unsupported::Optional)) } - fn serialize_some(self, _: &T) -> Result + fn serialize_some(self, _: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Err(self.bad_type(Unsupported::Optional)) } fn serialize_unit(self) -> Result { - Err(self.bad_type(Unsupported::Unit)) + let mut map = tri!(self.delegate.serialize_map(Some(1))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + map.end() } fn serialize_unit_struct(self, _: &'static str) -> Result { - let mut map = try!(self.delegate.serialize_map(Some(1))); - try!(map.serialize_entry(self.tag, self.variant_name)); + let mut map = tri!(self.delegate.serialize_map(Some(1))); + tri!(map.serialize_entry(self.tag, self.variant_name)); map.end() } @@ -199,24 +199,24 @@ where _: u32, inner_variant: &'static str, ) -> Result { - let mut map = try!(self.delegate.serialize_map(Some(2))); - try!(map.serialize_entry(self.tag, self.variant_name)); - try!(map.serialize_entry(inner_variant, &())); + let mut map = tri!(self.delegate.serialize_map(Some(2))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + tri!(map.serialize_entry(inner_variant, &())); map.end() } - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, _: &'static str, value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _: &'static str, _: u32, @@ -224,11 +224,11 @@ where inner_value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { - let mut map = try!(self.delegate.serialize_map(Some(2))); - try!(map.serialize_entry(self.tag, self.variant_name)); - try!(map.serialize_entry(inner_variant, inner_value)); + let mut map = tri!(self.delegate.serialize_map(Some(2))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + tri!(map.serialize_entry(inner_variant, inner_value)); map.end() } @@ -269,9 +269,9 @@ where inner_variant: &'static str, len: usize, ) -> Result { - let mut map = try!(self.delegate.serialize_map(Some(2))); - try!(map.serialize_entry(self.tag, self.variant_name)); - try!(map.serialize_key(inner_variant)); + let mut map = tri!(self.delegate.serialize_map(Some(2))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + tri!(map.serialize_key(inner_variant)); Ok(SerializeTupleVariantAsMapValue::new( map, inner_variant, @@ -280,8 +280,8 @@ where } fn serialize_map(self, len: Option) -> Result { - let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1))); - try!(map.serialize_entry(self.tag, self.variant_name)); + let mut map = tri!(self.delegate.serialize_map(len.map(|len| len + 1))); + tri!(map.serialize_entry(self.tag, self.variant_name)); Ok(map) } @@ -290,8 +290,8 @@ where name: &'static str, len: usize, ) -> Result { - let mut state = try!(self.delegate.serialize_struct(name, len + 1)); - try!(state.serialize_field(self.tag, self.variant_name)); + let mut state = tri!(self.delegate.serialize_struct(name, len + 1)); + tri!(state.serialize_field(self.tag, self.variant_name)); Ok(state) } @@ -316,9 +316,9 @@ where inner_variant: &'static str, len: usize, ) -> Result { - let mut map = try!(self.delegate.serialize_map(Some(2))); - try!(map.serialize_entry(self.tag, self.variant_name)); - try!(map.serialize_key(inner_variant)); + let mut map = tri!(self.delegate.serialize_map(Some(2))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + tri!(map.serialize_key(inner_variant)); Ok(SerializeStructVariantAsMapValue::new( map, inner_variant, @@ -327,46 +327,19 @@ where } #[cfg(not(any(feature = "std", feature = "alloc")))] - fn collect_str(self, _: &T) -> Result + fn collect_str(self, _: &T) -> Result where - T: Display, + T: ?Sized + Display, { Err(self.bad_type(Unsupported::String)) } } -/// Used only by Serde doc tests. Not public API. -#[doc(hidden)] -#[derive(Debug)] -pub struct Error; - -impl ser::Error for Error { - fn custom(_: T) -> Self - where - T: Display, - { - unimplemented!() - } -} - -#[cfg(feature = "std")] -impl error::Error for Error { - fn description(&self) -> &str { - unimplemented!() - } -} - -impl Display for Error { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - unimplemented!() - } -} - #[cfg(any(feature = "std", feature = "alloc"))] mod content { - use lib::*; + use crate::lib::*; - use ser::{self, Serialize, Serializer}; + use crate::ser::{self, Serialize, Serializer}; pub struct SerializeTupleVariantAsMapValue { map: M, @@ -377,13 +350,14 @@ mod content { impl SerializeTupleVariantAsMapValue { pub fn new(map: M, name: &'static str, len: usize) -> Self { SerializeTupleVariantAsMapValue { - map: map, - name: name, + map, + name, fields: Vec::with_capacity(len), } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue where M: ser::SerializeMap, @@ -391,17 +365,17 @@ mod content { type Ok = M::Ok; type Error = M::Error; - fn serialize_field(&mut self, value: &T) -> Result<(), M::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), M::Error> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); Ok(()) } fn end(mut self) -> Result { - try!(self + tri!(self .map .serialize_value(&Content::TupleStruct(self.name, self.fields))); self.map.end() @@ -417,13 +391,14 @@ mod content { impl SerializeStructVariantAsMapValue { pub fn new(map: M, name: &'static str, len: usize) -> Self { SerializeStructVariantAsMapValue { - map: map, - name: name, + map, + name, fields: Vec::with_capacity(len), } } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeStructVariant for SerializeStructVariantAsMapValue where M: ser::SerializeMap, @@ -431,28 +406,23 @@ mod content { type Ok = M::Ok; type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), M::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), M::Error> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); Ok(()) } fn end(mut self) -> Result { - try!(self + tri!(self .map .serialize_value(&Content::Struct(self.name, self.fields))); self.map.end() } } - #[derive(Debug)] pub enum Content { Bool(bool), @@ -496,6 +466,7 @@ mod content { ), } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl Serialize for Content { fn serialize(&self, serializer: S) -> Result where @@ -527,50 +498,50 @@ mod content { } Content::Seq(ref elements) => elements.serialize(serializer), Content::Tuple(ref elements) => { - use ser::SerializeTuple; - let mut tuple = try!(serializer.serialize_tuple(elements.len())); + use crate::ser::SerializeTuple; + let mut tuple = tri!(serializer.serialize_tuple(elements.len())); for e in elements { - try!(tuple.serialize_element(e)); + tri!(tuple.serialize_element(e)); } tuple.end() } Content::TupleStruct(n, ref fields) => { - use ser::SerializeTupleStruct; - let mut ts = try!(serializer.serialize_tuple_struct(n, fields.len())); + use crate::ser::SerializeTupleStruct; + let mut ts = tri!(serializer.serialize_tuple_struct(n, fields.len())); for f in fields { - try!(ts.serialize_field(f)); + tri!(ts.serialize_field(f)); } ts.end() } Content::TupleVariant(n, i, v, ref fields) => { - use ser::SerializeTupleVariant; - let mut tv = try!(serializer.serialize_tuple_variant(n, i, v, fields.len())); + use crate::ser::SerializeTupleVariant; + let mut tv = tri!(serializer.serialize_tuple_variant(n, i, v, fields.len())); for f in fields { - try!(tv.serialize_field(f)); + tri!(tv.serialize_field(f)); } tv.end() } Content::Map(ref entries) => { - use ser::SerializeMap; - let mut map = try!(serializer.serialize_map(Some(entries.len()))); - for &(ref k, ref v) in entries { - try!(map.serialize_entry(k, v)); + use crate::ser::SerializeMap; + let mut map = tri!(serializer.serialize_map(Some(entries.len()))); + for (k, v) in entries { + tri!(map.serialize_entry(k, v)); } map.end() } Content::Struct(n, ref fields) => { - use ser::SerializeStruct; - let mut s = try!(serializer.serialize_struct(n, fields.len())); + use crate::ser::SerializeStruct; + let mut s = tri!(serializer.serialize_struct(n, fields.len())); for &(k, ref v) in fields { - try!(s.serialize_field(k, v)); + tri!(s.serialize_field(k, v)); } s.end() } Content::StructVariant(n, i, v, ref fields) => { - use ser::SerializeStructVariant; - let mut sv = try!(serializer.serialize_struct_variant(n, i, v, fields.len())); + use crate::ser::SerializeStructVariant; + let mut sv = tri!(serializer.serialize_struct_variant(n, i, v, fields.len())); for &(k, ref v) in fields { - try!(sv.serialize_field(k, v)); + tri!(sv.serialize_field(k, v)); } sv.end() } @@ -588,6 +559,7 @@ mod content { } } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl Serializer for ContentSerializer where E: ser::Error, @@ -663,11 +635,11 @@ mod content { Ok(Content::None) } - fn serialize_some(self, value: &T) -> Result + fn serialize_some(self, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { - Ok(Content::Some(Box::new(try!(value.serialize(self))))) + Ok(Content::Some(Box::new(tri!(value.serialize(self))))) } fn serialize_unit(self) -> Result { @@ -687,21 +659,17 @@ mod content { Ok(Content::UnitVariant(name, variant_index, variant)) } - fn serialize_newtype_struct( - self, - name: &'static str, - value: &T, - ) -> Result + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Ok(Content::NewtypeStruct( name, - Box::new(try!(value.serialize(self))), + Box::new(tri!(value.serialize(self))), )) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, @@ -709,13 +677,13 @@ mod content { value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { Ok(Content::NewtypeVariant( name, variant_index, variant, - Box::new(try!(value.serialize(self))), + Box::new(tri!(value.serialize(self))), )) } @@ -739,7 +707,7 @@ mod content { len: usize, ) -> Result { Ok(SerializeTupleStruct { - name: name, + name, fields: Vec::with_capacity(len), error: PhantomData, }) @@ -753,9 +721,9 @@ mod content { len: usize, ) -> Result { Ok(SerializeTupleVariant { - name: name, - variant_index: variant_index, - variant: variant, + name, + variant_index, + variant, fields: Vec::with_capacity(len), error: PhantomData, }) @@ -775,7 +743,7 @@ mod content { len: usize, ) -> Result { Ok(SerializeStruct { - name: name, + name, fields: Vec::with_capacity(len), error: PhantomData, }) @@ -789,9 +757,9 @@ mod content { len: usize, ) -> Result { Ok(SerializeStructVariant { - name: name, - variant_index: variant_index, - variant: variant, + name, + variant_index, + variant, fields: Vec::with_capacity(len), error: PhantomData, }) @@ -803,6 +771,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeSeq for SerializeSeq where E: ser::Error, @@ -810,11 +779,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_element(&mut self, value: &T) -> Result<(), E> + fn serialize_element(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.elements.push(value); Ok(()) } @@ -829,6 +798,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeTuple for SerializeTuple where E: ser::Error, @@ -836,11 +806,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_element(&mut self, value: &T) -> Result<(), E> + fn serialize_element(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.elements.push(value); Ok(()) } @@ -856,6 +826,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeTupleStruct for SerializeTupleStruct where E: ser::Error, @@ -863,11 +834,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, value: &T) -> Result<(), E> + fn serialize_field(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); Ok(()) } @@ -885,6 +856,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeTupleVariant for SerializeTupleVariant where E: ser::Error, @@ -892,11 +864,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, value: &T) -> Result<(), E> + fn serialize_field(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push(value); Ok(()) } @@ -917,6 +889,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeMap for SerializeMap where E: ser::Error, @@ -924,24 +897,24 @@ mod content { type Ok = Content; type Error = E; - fn serialize_key(&mut self, key: &T) -> Result<(), E> + fn serialize_key(&mut self, key: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let key = try!(key.serialize(ContentSerializer::::new())); + let key = tri!(key.serialize(ContentSerializer::::new())); self.key = Some(key); Ok(()) } - fn serialize_value(&mut self, value: &T) -> Result<(), E> + fn serialize_value(&mut self, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { let key = self .key .take() .expect("serialize_value called before serialize_key"); - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.entries.push((key, value)); Ok(()) } @@ -950,13 +923,13 @@ mod content { Ok(Content::Map(self.entries)) } - fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), E> + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), E> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { - let key = try!(key.serialize(ContentSerializer::::new())); - let value = try!(value.serialize(ContentSerializer::::new())); + let key = tri!(key.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.entries.push((key, value)); Ok(()) } @@ -968,6 +941,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeStruct for SerializeStruct where E: ser::Error, @@ -975,11 +949,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); Ok(()) } @@ -997,6 +971,7 @@ mod content { error: PhantomData, } + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl ser::SerializeStructVariant for SerializeStructVariant where E: ser::Error, @@ -1004,11 +979,11 @@ mod content { type Ok = Content; type Error = E; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); Ok(()) } @@ -1041,6 +1016,7 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, M> Serializer for FlatMapSerializer<'a, M> where M: SerializeMap + 'a, @@ -1053,7 +1029,7 @@ where type SerializeTupleStruct = Impossible; type SerializeMap = FlatMapSerializeMap<'a, M>; type SerializeStruct = FlatMapSerializeStruct<'a, M>; - type SerializeTupleVariant = Impossible; + type SerializeTupleVariant = FlatMapSerializeTupleVariantAsMapValue<'a, M>; type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>; fn serialize_bool(self, _: bool) -> Result { @@ -1116,9 +1092,9 @@ where Ok(()) } - fn serialize_some(self, value: &T) -> Result + fn serialize_some(self, value: &T) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } @@ -1128,30 +1104,30 @@ where } fn serialize_unit_struct(self, _: &'static str) -> Result { - Err(Self::bad_type(Unsupported::UnitStruct)) + Ok(()) } fn serialize_unit_variant( self, _: &'static str, _: u32, - _: &'static str, + variant: &'static str, ) -> Result { - Err(Self::bad_type(Unsupported::Enum)) + self.0.serialize_entry(variant, &()) } - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, _: &'static str, value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { value.serialize(self) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _: &'static str, _: u32, @@ -1159,10 +1135,9 @@ where value: &T, ) -> Result where - T: Serialize, + T: ?Sized + Serialize, { - try!(self.0.serialize_key(variant)); - self.0.serialize_value(value) + self.0.serialize_entry(variant, value) } fn serialize_seq(self, _: Option) -> Result { @@ -1185,10 +1160,11 @@ where self, _: &'static str, _: u32, - _: &'static str, + variant: &'static str, _: usize, ) -> Result { - Err(Self::bad_type(Unsupported::Enum)) + tri!(self.0.serialize_key(variant)); + Ok(FlatMapSerializeTupleVariantAsMapValue::new(self.0)) } fn serialize_map(self, _: Option) -> Result { @@ -1210,7 +1186,7 @@ where inner_variant: &'static str, _: usize, ) -> Result { - try!(self.0.serialize_key(inner_variant)); + tri!(self.0.serialize_key(inner_variant)); Ok(FlatMapSerializeStructVariantAsMapValue::new( self.0, inner_variant, @@ -1222,6 +1198,7 @@ where pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M); #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M> where M: SerializeMap + 'a, @@ -1229,28 +1206,24 @@ where type Ok = (); type Error = M::Error; - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_key(key) } - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_value(value) } - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), Self::Error> + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { self.0.serialize_entry(key, value) } @@ -1264,6 +1237,7 @@ where pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M); #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M> where M: SerializeMap + 'a, @@ -1271,13 +1245,9 @@ where type Ok = (); type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { self.0.serialize_entry(key, value) } @@ -1287,6 +1257,53 @@ where } } +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializeTupleVariantAsMapValue<'a, M: 'a> { + map: &'a mut M, + fields: Vec, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializeTupleVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + fn new(map: &'a mut M) -> Self { + FlatMapSerializeTupleVariantAsMapValue { + map, + fields: Vec::new(), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, M> ser::SerializeTupleVariant for FlatMapSerializeTupleVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result<(), Self::Error> { + tri!(self.map.serialize_value(&Content::Seq(self.fields))); + Ok(()) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + #[cfg(any(feature = "std", feature = "alloc"))] pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> { map: &'a mut M, @@ -1301,14 +1318,15 @@ where { fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> { FlatMapSerializeStructVariantAsMapValue { - map: map, - name: name, + map, + name, fields: Vec::new(), } } } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M> where M: SerializeMap + 'a, @@ -1316,23 +1334,49 @@ where type Ok = (); type Error = M::Error; - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize, + T: ?Sized + Serialize, { - let value = try!(value.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); self.fields.push((key, value)); Ok(()) } fn end(self) -> Result<(), Self::Error> { - try!(self + tri!(self .map .serialize_value(&Content::Struct(self.name, self.fields))); Ok(()) } } + +pub struct AdjacentlyTaggedEnumVariant { + pub enum_name: &'static str, + pub variant_index: u32, + pub variant_name: &'static str, +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl Serialize for AdjacentlyTaggedEnumVariant { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name) + } +} + +// Error when Serialize for a non_exhaustive remote enum encounters a variant +// that is not recognized. +pub struct CannotSerializeVariant(pub T); + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl Display for CannotSerializeVariant +where + T: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "enum variant cannot be serialized: {:?}", self.0) + } +} diff --git a/serde_core/Cargo.toml b/serde_core/Cargo.toml new file mode 100644 index 000000000..6705c998a --- /dev/null +++ b/serde_core/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "serde_core" +version = "1.0.228" +authors = ["Erick Tryzelaar ", "David Tolnay "] +build = "build.rs" +categories = ["encoding", "no-std", "no-std::no-alloc"] +description = "Serde traits only, with no support for derive -- use the `serde` crate instead" +documentation = "https://docs.rs/serde_core" +edition = "2021" +homepage = "https://serde.rs" +keywords = ["serde", "serialization", "no_std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.56" + +[dev-dependencies] +serde = { version = "1", path = "../serde" } +serde_derive = { version = "1", path = "../serde_derive" } + +[package.metadata.playground] +features = ["rc", "result"] + +[package.metadata.docs.rs] +features = ["rc", "result", "unstable"] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] + +# This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's +# version in lockstep with serde's, even if someone depends on the two crates +# separately with serde's "derive" feature disabled. Every serde_derive release +# is compatible with exactly one serde release because the generated code +# involves nonpublic APIs which are not bound by semver. +[target.'cfg(any())'.dependencies] +serde_derive = { version = "=1.0.228", path = "../serde_derive" } + + +### FEATURES ################################################################# + +[features] +default = ["std", "result"] + +# Provide impls for common standard library types like Vec and HashMap. +# Requires a dependency on the Rust standard library. +std = [] + +# Provide impls for types that require unstable functionality. For tracking and +# discussion of unstable functionality please refer to this issue: +# +# https://github.com/serde-rs/serde/issues/812 +unstable = [] + +# Provide impls for types in the Rust core allocation and collections library +# including String, Box, Vec, and Cow. This is a subset of std but may +# be enabled without depending on all of std. +alloc = [] + +# Opt into impls for Rc and Arc. Serializing and deserializing these types +# does not preserve identity and may result in multiple copies of the same data. +# Be sure that this is what you want before enabling this feature. +rc = [] + +# Provide impls for Result. Convenient in some contexts but can lead to +# confusion if ? or unwrap are used incautiously. +result = [] diff --git a/serde_test/LICENSE-APACHE b/serde_core/LICENSE-APACHE similarity index 100% rename from serde_test/LICENSE-APACHE rename to serde_core/LICENSE-APACHE diff --git a/serde_test/LICENSE-MIT b/serde_core/LICENSE-MIT similarity index 100% rename from serde_test/LICENSE-MIT rename to serde_core/LICENSE-MIT diff --git a/serde_core/README.md b/serde_core/README.md new file mode 100644 index 000000000..94a765e28 --- /dev/null +++ b/serde_core/README.md @@ -0,0 +1,28 @@ +The `serde_core` crate contains Serde's trait definitions with **no support for +#\[derive()\]**. + +In crates that derive an implementation of `Serialize` or `Deserialize`, you +must depend on the [`serde`] crate, not `serde_core`. + +[`serde`]: https://crates.io/crates/serde + +In crates that handwrite implementations of Serde traits, or only use them as +trait bounds, depending on `serde_core` is permitted. But `serde` re-exports all +of these traits and can be used for this use case too. If in doubt, disregard +`serde_core` and always use `serde`. + +Crates that depend on `serde_core` instead of `serde` are able to compile in +parallel with `serde_derive` even when `serde`'s "derive" feature is turned on, +as shown in the following build timings. + +
+ +| When `serde_json` depends on `serde` | +|---| +| | + +
+ +| When `serde_json` depends on `serde_core` | +|---| +| | diff --git a/serde_core/build.rs b/serde_core/build.rs new file mode 100644 index 000000000..7092814a2 --- /dev/null +++ b/serde_core/build.rs @@ -0,0 +1,113 @@ +use std::env; +use std::fs; +use std::path::PathBuf; +use std::process::Command; +use std::str; + +const PRIVATE: &str = "\ +#[doc(hidden)] +pub mod __private$$ { + #[doc(hidden)] + pub use crate::private::*; +} +"; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap(); + let module = PRIVATE.replace("$$", &patch_version); + fs::write(out_dir.join("private.rs"), module).unwrap(); + + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + if minor >= 77 { + println!("cargo:rustc-check-cfg=cfg(if_docsrs_then_no_serde_core)"); + println!("cargo:rustc-check-cfg=cfg(no_core_cstr)"); + println!("cargo:rustc-check-cfg=cfg(no_core_error)"); + println!("cargo:rustc-check-cfg=cfg(no_core_net)"); + println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)"); + println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); + println!("cargo:rustc-check-cfg=cfg(no_serde_derive)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic)"); + println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)"); + println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)"); + } + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60. + if minor < 60 { + println!("cargo:rustc-cfg=no_target_has_atomic"); + // Allowlist of archs that support std::sync::atomic module. This is + // based on rustc's compiler/rustc_target/src/spec/*.rs. + let has_atomic64 = target.starts_with("x86_64") + || target.starts_with("i686") + || target.starts_with("aarch64") + || target.starts_with("powerpc64") + || target.starts_with("sparc64") + || target.starts_with("mips64el") + || target.starts_with("riscv64"); + let has_atomic32 = has_atomic64 || emscripten; + if minor < 34 || !has_atomic64 { + println!("cargo:rustc-cfg=no_std_atomic64"); + } + if minor < 34 || !has_atomic32 { + println!("cargo:rustc-cfg=no_std_atomic"); + } + } + + // Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64. + // https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc + if minor < 64 { + println!("cargo:rustc-cfg=no_core_cstr"); + } + + // Current minimum supported version of serde_derive crate is Rust 1.68. + if minor < 68 { + println!("cargo:rustc-cfg=no_serde_derive"); + } + + // Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74 + // https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis + if minor < 74 { + println!("cargo:rustc-cfg=no_core_num_saturating"); + } + + // Support for core::net stabilized in Rust 1.77. + // https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html + if minor < 77 { + println!("cargo:rustc-cfg=no_core_net"); + } + + // Support for the `#[diagnostic]` tool attribute namespace + // https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes + if minor < 78 { + println!("cargo:rustc-cfg=no_diagnostic_namespace"); + } + + // The Error trait became available in core in 1.81. + // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror + if minor < 81 { + println!("cargo:rustc-cfg=no_core_error"); + } +} + +fn rustc_minor_version() -> Option { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + pieces.next()?.parse().ok() +} diff --git a/serde_core/src/crate_root.rs b/serde_core/src/crate_root.rs new file mode 100644 index 000000000..2cf75a401 --- /dev/null +++ b/serde_core/src/crate_root.rs @@ -0,0 +1,171 @@ +macro_rules! crate_root { + () => { + /// A facade around all the types we need from the `std`, `core`, and `alloc` + /// crates. This avoids elaborate import wrangling having to happen in every + /// module. + mod lib { + mod core { + #[cfg(not(feature = "std"))] + pub use core::*; + #[cfg(feature = "std")] + pub use std::*; + } + + pub use self::core::{f32, f64}; + pub use self::core::{iter, num, str}; + + #[cfg(any(feature = "std", feature = "alloc"))] + pub use self::core::{cmp, mem}; + + pub use self::core::cell::{Cell, RefCell}; + pub use self::core::cmp::Reverse; + pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite}; + pub use self::core::marker::PhantomData; + pub use self::core::num::Wrapping; + pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo}; + pub use self::core::result; + pub use self::core::time::Duration; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::borrow::{Cow, ToOwned}; + #[cfg(feature = "std")] + pub use std::borrow::{Cow, ToOwned}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::{String, ToString}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::vec::Vec; + #[cfg(feature = "std")] + pub use std::vec::Vec; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::boxed::Box; + #[cfg(feature = "std")] + pub use std::boxed::Box; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::rc::{Rc, Weak as RcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::rc::{Rc, Weak as RcWeak}; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::sync::{Arc, Weak as ArcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::sync::{Arc, Weak as ArcWeak}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + #[cfg(feature = "std")] + pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + + #[cfg(all(not(no_core_cstr), not(feature = "std")))] + pub use self::core::ffi::CStr; + #[cfg(feature = "std")] + pub use std::ffi::CStr; + + #[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))] + pub use alloc::ffi::CString; + #[cfg(feature = "std")] + pub use std::ffi::CString; + + #[cfg(all(not(no_core_net), not(feature = "std")))] + pub use self::core::net; + #[cfg(feature = "std")] + pub use std::net; + + #[cfg(feature = "std")] + pub use std::error; + + #[cfg(feature = "std")] + pub use std::collections::{HashMap, HashSet}; + #[cfg(feature = "std")] + pub use std::ffi::{OsStr, OsString}; + #[cfg(feature = "std")] + pub use std::hash::{BuildHasher, Hash}; + #[cfg(feature = "std")] + pub use std::io::Write; + #[cfg(feature = "std")] + pub use std::path::{Path, PathBuf}; + #[cfg(feature = "std")] + pub use std::sync::{Mutex, RwLock}; + #[cfg(feature = "std")] + pub use std::time::{SystemTime, UNIX_EPOCH}; + + #[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))] + pub use std::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU8, AtomicUsize, Ordering, + }; + #[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))] + pub use std::sync::atomic::{AtomicI64, AtomicU64}; + + #[cfg(all(feature = "std", not(no_target_has_atomic)))] + pub use std::sync::atomic::Ordering; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))] + pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))] + pub use std::sync::atomic::{AtomicI16, AtomicU16}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))] + pub use std::sync::atomic::{AtomicI32, AtomicU32}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))] + pub use std::sync::atomic::{AtomicI64, AtomicU64}; + #[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))] + pub use std::sync::atomic::{AtomicIsize, AtomicUsize}; + + #[cfg(not(no_core_num_saturating))] + pub use self::core::num::Saturating; + } + + // None of this crate's error handling needs the `From::from` error conversion + // performed implicitly by the `?` operator or the standard library's `try!` + // macro. This simplified macro gives a 5.5% improvement in compile time + // compared to standard `try!`, and 9% improvement compared to `?`. + macro_rules! tri { + ($expr:expr) => { + match $expr { + Ok(val) => val, + Err(err) => return Err(err), + } + }; + } + + #[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/de/mod.rs")] + pub mod de; + #[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/ser/mod.rs")] + pub mod ser; + + #[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/format.rs")] + mod format; + + #[doc(inline)] + pub use crate::de::{Deserialize, Deserializer}; + #[doc(inline)] + pub use crate::ser::{Serialize, Serializer}; + + // Used by generated code. Not public API. + #[doc(hidden)] + #[cfg_attr( + all(docsrs, if_docsrs_then_no_serde_core), + path = "core/private/mod.rs" + )] + mod private; + + // Used by declarative macro generated code. Not public API. + #[doc(hidden)] + pub mod __private { + #[doc(hidden)] + pub use crate::private::doc; + #[doc(hidden)] + pub use core::result::Result; + } + + include!(concat!(env!("OUT_DIR"), "/private.rs")); + + #[cfg(all(not(feature = "std"), no_core_error))] + #[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/std_error.rs")] + mod std_error; + }; +} diff --git a/serde/src/de/ignored_any.rs b/serde_core/src/de/ignored_any.rs similarity index 91% rename from serde/src/de/ignored_any.rs rename to serde_core/src/de/ignored_any.rs index 68a644e0d..2360a1742 100644 --- a/serde/src/de/ignored_any.rs +++ b/serde_core/src/de/ignored_any.rs @@ -1,6 +1,6 @@ -use lib::*; +use crate::lib::*; -use de::{ +use crate::de::{ Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor, }; @@ -10,13 +10,12 @@ use de::{ /// any type, except that it does not store any information about the data that /// gets deserialized. /// -/// ```edition2018 -/// use std::fmt; -/// use std::marker::PhantomData; -/// +/// ```edition2021 /// use serde::de::{ /// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor, /// }; +/// use std::fmt; +/// use std::marker::PhantomData; /// /// /// A seed that can be used to deserialize only the `n`th element of a sequence /// /// while efficiently discarding elements of any type before or after index `n`. @@ -108,7 +107,7 @@ use de::{ /// # Ok(()) /// # } /// ``` -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct IgnoredAny; impl<'de> Visitor<'de> for IgnoredAny { @@ -130,12 +129,24 @@ impl<'de> Visitor<'de> for IgnoredAny { Ok(IgnoredAny) } + #[inline] + fn visit_i128(self, x: i128) -> Result { + let _ = x; + Ok(IgnoredAny) + } + #[inline] fn visit_u64(self, x: u64) -> Result { let _ = x; Ok(IgnoredAny) } + #[inline] + fn visit_u128(self, x: u128) -> Result { + let _ = x; + Ok(IgnoredAny) + } + #[inline] fn visit_f64(self, x: f64) -> Result { let _ = x; @@ -182,7 +193,7 @@ impl<'de> Visitor<'de> for IgnoredAny { where A: SeqAccess<'de>, { - while let Some(IgnoredAny) = try!(seq.next_element()) { + while let Some(IgnoredAny) = tri!(seq.next_element()) { // Gobble } Ok(IgnoredAny) @@ -193,7 +204,7 @@ impl<'de> Visitor<'de> for IgnoredAny { where A: MapAccess<'de>, { - while let Some((IgnoredAny, IgnoredAny)) = try!(map.next_entry()) { + while let Some((IgnoredAny, IgnoredAny)) = tri!(map.next_entry()) { // Gobble } Ok(IgnoredAny) @@ -212,7 +223,7 @@ impl<'de> Visitor<'de> for IgnoredAny { where A: EnumAccess<'de>, { - data.variant::()?.1.newtype_variant() + tri!(data.variant::()).1.newtype_variant() } } diff --git a/serde/src/de/impls.rs b/serde_core/src/de/impls.rs similarity index 63% rename from serde/src/de/impls.rs rename to serde_core/src/de/impls.rs index d9af210e4..ab1a893cc 100644 --- a/serde/src/de/impls.rs +++ b/serde_core/src/de/impls.rs @@ -1,17 +1,13 @@ -use lib::*; +use crate::lib::*; -use de::{ - Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess, Visitor, +use crate::de::{ + Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, Unexpected, VariantAccess, + Visitor, }; - -#[cfg(any(core_duration, feature = "std", feature = "alloc"))] -use de::MapAccess; - -use de::from_primitive::FromPrimitive; -use private::de::InPlaceSeed; +use crate::private::{self, InPlaceSeed}; #[cfg(any(feature = "std", feature = "alloc"))] -use private::de::size_hint; +use crate::private::size_hint; //////////////////////////////////////////////////////////////////////////////// @@ -42,6 +38,7 @@ impl<'de> Deserialize<'de> for () { } #[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl<'de> Deserialize<'de> for ! { fn deserialize(_deserializer: D) -> Result where @@ -81,39 +78,56 @@ impl<'de> Deserialize<'de> for bool { //////////////////////////////////////////////////////////////////////////////// -macro_rules! visit_integer_method { - ($src_ty:ident, $method:ident, $from_method:ident, $group:ident, $group_ty:ident) => { - #[inline] - fn $method(self, v: $src_ty) -> Result - where - E: Error, - { - match FromPrimitive::$from_method(v) { - Some(v) => Ok(v), - None => Err(Error::invalid_value( - Unexpected::$group(v as $group_ty), - &self, - )), +macro_rules! impl_deserialize_num { + ($primitive:ident, $nonzero:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => { + impl_deserialize_num!($primitive, $deserialize $($method!($($val : $visit)*);)*); + + impl<'de> Deserialize<'de> for num::$nonzero { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct NonZeroVisitor; + + impl<'de> Visitor<'de> for NonZeroVisitor { + type Value = num::$nonzero; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a nonzero ", stringify!($primitive))) + } + + $($($method!(nonzero $primitive $val : $visit);)*)* + } + + deserializer.$deserialize(NonZeroVisitor) } } - }; -} -macro_rules! visit_float_method { - ($src_ty:ident, $method:ident) => { - #[inline] - fn $method(self, v: $src_ty) -> Result - where - E: Error, - { - Ok(v as Self::Value) + #[cfg(not(no_core_num_saturating))] + impl<'de> Deserialize<'de> for Saturating<$primitive> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SaturatingVisitor; + + impl<'de> Visitor<'de> for SaturatingVisitor { + type Value = Saturating<$primitive>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("integer with support for saturating semantics") + } + + $($($method!(saturating $primitive $val : $visit);)*)* + } + + deserializer.$deserialize(SaturatingVisitor) + } } }; -} -macro_rules! impl_deserialize_num { - ($ty:ident, $method:ident, $($visit:ident),*) => { - impl<'de> Deserialize<'de> for $ty { + ($primitive:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => { + impl<'de> Deserialize<'de> for $primitive { #[inline] fn deserialize(deserializer: D) -> Result where @@ -122,139 +136,400 @@ macro_rules! impl_deserialize_num { struct PrimitiveVisitor; impl<'de> Visitor<'de> for PrimitiveVisitor { - type Value = $ty; + type Value = $primitive; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(stringify!($ty)) + formatter.write_str(stringify!($primitive)) } - $( - impl_deserialize_num!($visit $ty); - )* + $($($method!($val : $visit);)*)* } - deserializer.$method(PrimitiveVisitor) + deserializer.$deserialize(PrimitiveVisitor) } } }; +} - (integer $ty:ident) => { - visit_integer_method!(i8, visit_i8, from_i8, Signed, i64); - visit_integer_method!(i16, visit_i16, from_i16, Signed, i64); - visit_integer_method!(i32, visit_i32, from_i32, Signed, i64); - visit_integer_method!(i64, visit_i64, from_i64, Signed, i64); +macro_rules! num_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v) + } + }; - visit_integer_method!(u8, visit_u8, from_u8, Unsigned, u64); - visit_integer_method!(u16, visit_u16, from_u16, Unsigned, u64); - visit_integer_method!(u32, visit_u32, from_u32, Unsigned, u64); - visit_integer_method!(u64, visit_u64, from_u64, Unsigned, u64); + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if let Some(nonzero) = Self::Value::new(v) { + Ok(nonzero) + } else { + Err(Error::invalid_value(Unexpected::Unsigned(0), &self)) + } + } }; - (float $ty:ident) => { - visit_float_method!(f32, visit_f32); - visit_float_method!(f64, visit_f64); + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v)) + } }; } -impl_deserialize_num!(i8, deserialize_i8, integer); -impl_deserialize_num!(i16, deserialize_i16, integer); -impl_deserialize_num!(i32, deserialize_i32, integer); -impl_deserialize_num!(i64, deserialize_i64, integer); -impl_deserialize_num!(isize, deserialize_i64, integer); +macro_rules! num_as_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v as Self::Value) + } + }; -impl_deserialize_num!(u8, deserialize_u8, integer); -impl_deserialize_num!(u16, deserialize_u16, integer); -impl_deserialize_num!(u32, deserialize_u32, integer); -impl_deserialize_num!(u64, deserialize_u64, integer); -impl_deserialize_num!(usize, deserialize_u64, integer); + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if let Some(nonzero) = Self::Value::new(v as $primitive) { + Ok(nonzero) + } else { + Err(Error::invalid_value(Unexpected::Unsigned(0), &self)) + } + } + }; -impl_deserialize_num!(f32, deserialize_f32, integer, float); -impl_deserialize_num!(f64, deserialize_f64, integer, float); + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v as $primitive)) + } + }; +} -serde_if_integer128! { - impl<'de> Deserialize<'de> for i128 { +macro_rules! num_as_copysign_self { + ($ty:ident : $visit:ident) => { #[inline] - fn deserialize(deserializer: D) -> Result + fn $visit(self, v: $ty) -> Result where - D: Deserializer<'de>, + E: Error, { - struct PrimitiveVisitor; + #[cfg(not(feature = "std"))] + { + Ok(v as Self::Value) + } - impl<'de> Visitor<'de> for PrimitiveVisitor { - type Value = i128; + #[cfg(feature = "std")] + { + // Preserve sign of NaN. The `as` produces a nondeterministic sign. + let sign = if v.is_sign_positive() { 1.0 } else { -1.0 }; + Ok((v as Self::Value).copysign(sign)) + } + } + }; +} - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("i128") +macro_rules! int_to_int { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Self::Value::try_from(v as i64) + .map_err(|_| Error::invalid_value(Unexpected::Signed(v as i64), &self)) + } + }; + + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if let Ok(v) = $primitive::try_from(v as i64) { + if let Some(nonzero) = Self::Value::new(v) { + return Ok(nonzero); } + } + Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) + } + }; - impl_deserialize_num!(integer i128); + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if (v as i64) < $primitive::MIN as i64 { + Ok(Saturating($primitive::MIN)) + } else if ($primitive::MAX as i64) < v as i64 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } + } + }; +} - #[inline] - fn visit_i128(self, v: i128) -> Result - where - E: Error, - { - Ok(v) +macro_rules! int_to_uint { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if 0 <= v { + #[allow(irrefutable_let_patterns)] + if let Ok(v) = Self::Value::try_from(v as u64) { + return Ok(v as Self::Value); } + } + Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) + } + }; - #[inline] - fn visit_u128(self, v: u128) -> Result - where - E: Error, - { - if v <= i128::max_value() as u128 { - Ok(v as i128) - } else { - Err(Error::invalid_value(Unexpected::Other("u128"), &self)) + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if 0 < v { + #[allow(irrefutable_let_patterns)] + if let Ok(v) = $primitive::try_from(v as u64) { + if let Some(nonzero) = Self::Value::new(v) { + return Ok(nonzero); } } } + Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) + } + }; - deserializer.deserialize_i128(PrimitiveVisitor) + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if v < 0 { + Ok(Saturating(0)) + } else if ($primitive::MAX as u64) < v as u64 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } } - } + }; +} - impl<'de> Deserialize<'de> for u128 { +macro_rules! uint_to_self { + ($ty:ident : $visit:ident) => { #[inline] - fn deserialize(deserializer: D) -> Result + fn $visit(self, v: $ty) -> Result where - D: Deserializer<'de>, + E: Error, { - struct PrimitiveVisitor; - - impl<'de> Visitor<'de> for PrimitiveVisitor { - type Value = u128; + Self::Value::try_from(v as u64) + .map_err(|_| Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) + } + }; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("u128") + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if let Ok(v) = $primitive::try_from(v as u64) { + if let Some(nonzero) = Self::Value::new(v) { + return Ok(nonzero); } + } + Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) + } + }; - impl_deserialize_num!(integer u128); + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if let Ok(v) = $primitive::try_from(v as u64) { + Ok(Saturating(v as $primitive)) + } else { + Ok(Saturating($primitive::MAX)) + } + } + }; +} - #[inline] - fn visit_i128(self, v: i128) -> Result - where - E: Error, - { - if v >= 0 { - Ok(v as u128) - } else { - Err(Error::invalid_value(Unexpected::Other("i128"), &self)) - } - } +impl_deserialize_num! { + i8, NonZeroI8, deserialize_i8 + num_self!(i8:visit_i8); + int_to_int!(i16:visit_i16 i32:visit_i32 i64:visit_i64); + uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} - #[inline] - fn visit_u128(self, v: u128) -> Result - where - E: Error, - { - Ok(v) +impl_deserialize_num! { + i16, NonZeroI16, deserialize_i16 + num_self!(i16:visit_i16); + num_as_self!(i8:visit_i8); + int_to_int!(i32:visit_i32 i64:visit_i64); + uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + i32, NonZeroI32, deserialize_i32 + num_self!(i32:visit_i32); + num_as_self!(i8:visit_i8 i16:visit_i16); + int_to_int!(i64:visit_i64); + uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + i64, NonZeroI64, deserialize_i64 + num_self!(i64:visit_i64); + num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32); + uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + isize, NonZeroIsize, deserialize_i64 + num_as_self!(i8:visit_i8 i16:visit_i16); + int_to_int!(i32:visit_i32 i64:visit_i64); + uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + u8, NonZeroU8, deserialize_u8 + num_self!(u8:visit_u8); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + uint_to_self!(u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + u16, NonZeroU16, deserialize_u16 + num_self!(u16:visit_u16); + num_as_self!(u8:visit_u8); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + uint_to_self!(u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + u32, NonZeroU32, deserialize_u32 + num_self!(u32:visit_u32); + num_as_self!(u8:visit_u8 u16:visit_u16); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + uint_to_self!(u64:visit_u64); +} + +impl_deserialize_num! { + u64, NonZeroU64, deserialize_u64 + num_self!(u64:visit_u64); + num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); +} + +impl_deserialize_num! { + usize, NonZeroUsize, deserialize_u64 + num_as_self!(u8:visit_u8 u16:visit_u16); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + uint_to_self!(u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + f32, deserialize_f32 + num_self!(f32:visit_f32); + num_as_copysign_self!(f64:visit_f64); + num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +impl_deserialize_num! { + f64, deserialize_f64 + num_self!(f64:visit_f64); + num_as_copysign_self!(f32:visit_f32); + num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); +} + +macro_rules! num_128 { + ($ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if v as i128 >= Self::Value::MIN as i128 && v as u128 <= Self::Value::MAX as u128 { + Ok(v as Self::Value) + } else { + Err(Error::invalid_value( + Unexpected::Other(stringify!($ty)), + &self, + )) + } + } + }; + + (nonzero $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if v as i128 >= $primitive::MIN as i128 && v as u128 <= $primitive::MAX as u128 { + if let Some(nonzero) = Self::Value::new(v as $primitive) { + Ok(nonzero) + } else { + Err(Error::invalid_value(Unexpected::Unsigned(0), &self)) } + } else { + Err(Error::invalid_value( + Unexpected::Other(stringify!($ty)), + &self, + )) } + } + }; - deserializer.deserialize_u128(PrimitiveVisitor) + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + if (v as i128) < $primitive::MIN as i128 { + Ok(Saturating($primitive::MIN)) + } else if ($primitive::MAX as u128) < v as u128 { + Ok(Saturating($primitive::MAX)) + } else { + Ok(Saturating(v as $primitive)) + } } - } + }; +} + +impl_deserialize_num! { + i128, NonZeroI128, deserialize_i128 + num_self!(i128:visit_i128); + num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); + num_128!(u128:visit_u128); +} + +impl_deserialize_num! { + u128, NonZeroU128, deserialize_u128 + num_self!(u128:visit_u128); + num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64); + int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64); + num_128!(i128:visit_i128); } //////////////////////////////////////////////////////////////////////////////// @@ -409,6 +684,7 @@ impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> { } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de> Deserialize<'de> for String { fn deserialize(deserializer: D) -> Result where @@ -497,10 +773,10 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] { //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] struct CStringVisitor; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] impl<'de> Visitor<'de> for CStringVisitor { type Value = CString; @@ -512,10 +788,10 @@ impl<'de> Visitor<'de> for CStringVisitor { where A: SeqAccess<'de>, { - let len = size_hint::cautious(seq.size_hint()); - let mut values = Vec::with_capacity(len); + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); - while let Some(value) = try!(seq.next_element()) { + while let Some(value) = tri!(seq.next_element()) { values.push(value); } @@ -551,7 +827,8 @@ impl<'de> Visitor<'de> for CStringVisitor { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de> Deserialize<'de> for CString { fn deserialize(deserializer: D) -> Result where @@ -563,10 +840,10 @@ impl<'de> Deserialize<'de> for CString { macro_rules! forwarded_impl { ( - $(#[doc = $doc:tt])* - ( $($id: ident),* ), $ty: ty, $func: expr + $(#[$attr:meta])* + ($($id:ident),*), $ty:ty, $func:expr ) => { - $(#[doc = $doc])* + $(#[$attr])* impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where @@ -578,11 +855,15 @@ macro_rules! forwarded_impl { } } -#[cfg(all(feature = "std", de_boxed_c_str))] -forwarded_impl!((), Box, CString::into_boxed_c_str); +forwarded_impl! { + #[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (), Box, CString::into_boxed_c_str +} -#[cfg(core_reverse)] -forwarded_impl!((T), Reverse, Reverse); +forwarded_impl! { + (T), Reverse, Reverse +} //////////////////////////////////////////////////////////////////////////////// @@ -624,7 +905,6 @@ where T::deserialize(deserializer).map(Some) } - #[doc(hidden)] fn __private_visit_untagged_option(self, deserializer: D) -> Result where D: Deserializer<'de>, @@ -659,7 +939,10 @@ struct PhantomDataVisitor { marker: PhantomData, } -impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor { +impl<'de, T> Visitor<'de> for PhantomDataVisitor +where + T: ?Sized, +{ type Value = PhantomData; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -675,7 +958,10 @@ impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor { } } -impl<'de, T: ?Sized> Deserialize<'de> for PhantomData { +impl<'de, T> Deserialize<'de> for PhantomData +where + T: ?Sized, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -689,16 +975,17 @@ impl<'de, T: ?Sized> Deserialize<'de> for PhantomData { //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! seq_impl { ( - $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, + $(#[$attr:meta])* + $ty:ident , $access:ident, $clear:expr, $with_capacity:expr, $reserve:expr, $insert:expr ) => { + $(#[$attr])* impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty where T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, @@ -730,7 +1017,7 @@ macro_rules! seq_impl { { let mut values = $with_capacity; - while let Some(value) = try!($access.next_element()) { + while let Some(value) = tri!($access.next_element()) { $insert(&mut values, value); } @@ -765,10 +1052,10 @@ macro_rules! seq_impl { A: SeqAccess<'de>, { $clear(&mut self.0); - $reserve(&mut self.0, size_hint::cautious($access.size_hint())); + $reserve(&mut self.0, size_hint::cautious::($access.size_hint())); // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) - while let Some(value) = try!($access.next_element()) { + while let Some(value) = tri!($access.next_element()) { $insert(&mut self.0, value); } @@ -786,18 +1073,20 @@ macro_rules! seq_impl { #[cfg(any(feature = "std", feature = "alloc"))] fn nop_reserve(_seq: T, _n: usize) {} -#[cfg(any(feature = "std", feature = "alloc"))] seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] BinaryHeap, seq, BinaryHeap::clear, - BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), + BinaryHeap::with_capacity(size_hint::cautious::(seq.size_hint())), BinaryHeap::reserve, BinaryHeap::push ); -#[cfg(any(feature = "std", feature = "alloc"))] seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] BTreeSet, seq, BTreeSet::clear, @@ -806,8 +1095,9 @@ seq_impl!( BTreeSet::insert ); -#[cfg(any(feature = "std", feature = "alloc"))] seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] LinkedList, seq, LinkedList::clear, @@ -816,21 +1106,24 @@ seq_impl!( LinkedList::push_back ); -#[cfg(feature = "std")] seq_impl!( + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] HashSet, seq, HashSet::clear, - HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), + HashSet::with_capacity_and_hasher(size_hint::cautious::(seq.size_hint()), S::default()), HashSet::reserve, - HashSet::insert); + HashSet::insert +); -#[cfg(any(feature = "std", feature = "alloc"))] seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] VecDeque, seq, VecDeque::clear, - VecDeque::with_capacity(size_hint::cautious(seq.size_hint())), + VecDeque::with_capacity(size_hint::cautious::(seq.size_hint())), VecDeque::reserve, VecDeque::push_back ); @@ -838,6 +1131,7 @@ seq_impl!( //////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, T> Deserialize<'de> for Vec where T: Deserialize<'de>, @@ -864,9 +1158,10 @@ where where A: SeqAccess<'de>, { - let mut values = Vec::with_capacity(size_hint::cautious(seq.size_hint())); + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); - while let Some(value) = try!(seq.next_element()) { + while let Some(value) = tri!(seq.next_element()) { values.push(value); } @@ -900,7 +1195,7 @@ where where A: SeqAccess<'de>, { - let hint = size_hint::cautious(seq.size_hint()); + let hint = size_hint::cautious::(seq.size_hint()); if let Some(additional) = hint.checked_sub(self.0.len()) { self.0.reserve(additional); } @@ -908,7 +1203,7 @@ where for i in 0..self.0.len() { let next = { let next_place = InPlaceSeed(&mut self.0[i]); - try!(seq.next_element_seed(next_place)) + tri!(seq.next_element_seed(next_place)) }; if next.is_none() { self.0.truncate(i); @@ -916,7 +1211,7 @@ where } } - while let Some(value) = try!(seq.next_element()) { + while let Some(value) = tri!(seq.next_element()) { self.0.push(value); } @@ -988,7 +1283,7 @@ macro_rules! array_impls { A: SeqAccess<'de>, { Ok([$( - match try!(seq.next_element()) { + match tri!(seq.next_element()) { Some(val) => val, None => return Err(Error::invalid_length($n, &self)), } @@ -1013,7 +1308,7 @@ macro_rules! array_impls { { let mut fail_idx = None; for (idx, dest) in self.0[..].iter_mut().enumerate() { - if try!(seq.next_element_seed(InPlaceSeed(dest))).is_none() { + if tri!(seq.next_element_seed(InPlaceSeed(dest))).is_none() { fail_idx = Some(idx); break; } @@ -1087,82 +1382,103 @@ array_impls! { macro_rules! tuple_impls { ($($len:tt => ($($n:tt $name:ident)+))+) => { $( - impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct TupleVisitor<$($name,)+> { - marker: PhantomData<($($name,)+)>, - } + #[cfg_attr(docsrs, doc(hidden))] + impl<'de, $($name),+> Deserialize<'de> for ($($name,)+) + where + $($name: Deserialize<'de>,)+ + { + tuple_impl_body!($len => ($($n $name)+)); + } + )+ + }; +} - impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { - type Value = ($($name,)+); +macro_rules! tuple_impl_body { + ($len:tt => ($($n:tt $name:ident)+)) => { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct TupleVisitor<$($name,)+> { + marker: PhantomData<($($name,)+)>, + } - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(concat!("a tuple of size ", $len)) - } + impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { + type Value = ($($name,)+); - #[inline] - #[allow(non_snake_case)] - fn visit_seq
(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - $( - let $name = match try!(seq.next_element()) { - Some(value) => value, - None => return Err(Error::invalid_length($n, &self)), - }; - )+ - - Ok(($($name,)+)) - } - } - - deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) - } + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } #[inline] - fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + #[allow(non_snake_case)] + fn visit_seq(self, mut seq: A) -> Result where - D: Deserializer<'de>, + A: SeqAccess<'de>, { - struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+)); + $( + let $name = match tri!(seq.next_element()) { + Some(value) => value, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ - impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> { - type Value = (); + Ok(($($name,)+)) + } + } - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(concat!("a tuple of size ", $len)) - } + deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) + } - #[inline] - #[allow(non_snake_case)] - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - $( - if try!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() { - return Err(Error::invalid_length($n, &self)); - } - )+ + #[inline] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+)); - Ok(()) + impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } + + #[inline] + #[allow(non_snake_case)] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + $( + if tri!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() { + return Err(Error::invalid_length($n, &self)); } - } + )+ - deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place)) + Ok(()) } } - )+ - } + + deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place)) + } + }; +} + +#[cfg_attr(docsrs, doc(fake_variadic))] +#[cfg_attr( + docsrs, + doc = "This trait is implemented for tuples up to 16 items long." +)] +impl<'de, T> Deserialize<'de> for (T,) +where + T: Deserialize<'de>, +{ + tuple_impl_body!(1 => (0 T)); } tuple_impls! { - 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) @@ -1182,13 +1498,14 @@ tuple_impls! { //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! map_impl { ( - $ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, + $(#[$attr:meta])* + $ty:ident , $access:ident, - $with_capacity:expr + $with_capacity:expr, ) => { + $(#[$attr])* impl<'de, K, V $(, $typaram)*> Deserialize<'de> for $ty where K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, @@ -1222,7 +1539,7 @@ macro_rules! map_impl { { let mut values = $with_capacity; - while let Some((key, value)) = try!($access.next_entry()) { + while let Some((key, value)) = tri!($access.next_entry()) { values.insert(key, value); } @@ -1237,47 +1554,34 @@ macro_rules! map_impl { } } -#[cfg(any(feature = "std", feature = "alloc"))] -map_impl!( +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] BTreeMap, map, - BTreeMap::new()); + BTreeMap::new(), +} -#[cfg(feature = "std")] -map_impl!( +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] HashMap, map, - HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())); + HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default()), +} //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] macro_rules! parse_ip_impl { - ($expecting:tt $ty:ty; $size:tt) => { + ($ty:ty, $expecting:expr, $size:tt) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { - struct IpAddrVisitor; - - impl<'de> Visitor<'de> for IpAddrVisitor { - type Value = $ty; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str($expecting) - } - - fn visit_str(self, s: &str) -> Result - where - E: Error, - { - s.parse().map_err(Error::custom) - } - } - - deserializer.deserialize_str(IpAddrVisitor) + deserializer.deserialize_str(FromStrVisitor::new($expecting)) } else { <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) } @@ -1286,18 +1590,18 @@ macro_rules! parse_ip_impl { }; } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] macro_rules! variant_identifier { ( - $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) - $expecting_message: expr, - $variants_name: ident + $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*) + $expecting_message:expr, + $variants_name:ident ) => { enum $name_kind { - $( $variant ),* + $($variant),* } - static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*]; + static $variants_name: &[&str] = &[$(stringify!($variant)),*]; impl<'de> Deserialize<'de> for $name_kind { fn deserialize(deserializer: D) -> Result @@ -1361,15 +1665,15 @@ macro_rules! variant_identifier { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] macro_rules! deserialize_enum { ( - $name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) - $expecting_message: expr, - $deserializer: expr + $name:ident $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*) + $expecting_message:expr, + $deserializer:expr ) => { - variant_identifier!{ - $name_kind ( $($variant; $bytes; $index),* ) + variant_identifier! { + $name_kind ($($variant; $bytes; $index),*) $expecting_message, VARIANTS } @@ -1387,7 +1691,7 @@ macro_rules! deserialize_enum { where A: EnumAccess<'de>, { - match try!(data.variant()) { + match tri!(data.variant()) { $( ($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant), )* @@ -1398,33 +1702,16 @@ macro_rules! deserialize_enum { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl<'de> Deserialize<'de> for net::IpAddr { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { - struct IpAddrVisitor; - - impl<'de> Visitor<'de> for IpAddrVisitor { - type Value = net::IpAddr; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("IP address") - } - - fn visit_str(self, s: &str) -> Result - where - E: Error, - { - s.parse().map_err(Error::custom) - } - } - - deserializer.deserialize_str(IpAddrVisitor) + deserializer.deserialize_str(FromStrVisitor::new("IP address")) } else { - use lib::net::IpAddr; + use crate::lib::net::IpAddr; deserialize_enum! { IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) "`V4` or `V6`", @@ -1434,74 +1721,43 @@ impl<'de> Deserialize<'de> for net::IpAddr { } } -#[cfg(feature = "std")] -parse_ip_impl!("IPv4 address" net::Ipv4Addr; 4); +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4); -#[cfg(feature = "std")] -parse_ip_impl!("IPv6 address" net::Ipv6Addr; 16); +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16); -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] macro_rules! parse_socket_impl { - ($expecting:tt $ty:ty, $new:expr) => { + ( + $ty:ty, $expecting:tt, + $new:expr, + ) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { - struct SocketAddrVisitor; - - impl<'de> Visitor<'de> for SocketAddrVisitor { - type Value = $ty; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str($expecting) - } - - fn visit_str(self, s: &str) -> Result - where - E: Error, - { - s.parse().map_err(Error::custom) - } - } - - deserializer.deserialize_str(SocketAddrVisitor) + deserializer.deserialize_str(FromStrVisitor::new($expecting)) } else { - <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port)) + <(_, u16)>::deserialize(deserializer).map($new) } } } }; } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl<'de> Deserialize<'de> for net::SocketAddr { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { - struct SocketAddrVisitor; - - impl<'de> Visitor<'de> for SocketAddrVisitor { - type Value = net::SocketAddr; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("socket address") - } - - fn visit_str(self, s: &str) -> Result - where - E: Error, - { - s.parse().map_err(Error::custom) - } - } - - deserializer.deserialize_str(SocketAddrVisitor) + deserializer.deserialize_str(FromStrVisitor::new("socket address")) } else { - use lib::net::SocketAddr; + use crate::lib::net::SocketAddr; deserialize_enum! { SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) "`V4` or `V6`", @@ -1511,13 +1767,17 @@ impl<'de> Deserialize<'de> for net::SocketAddr { } } -#[cfg(feature = "std")] -parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, net::SocketAddrV4::new); +#[cfg(any(feature = "std", not(no_core_net)))] +parse_socket_impl! { + net::SocketAddrV4, "IPv4 socket address", + |(ip, port)| net::SocketAddrV4::new(ip, port), +} -#[cfg(feature = "std")] -parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new( - ip, port, 0, 0 -)); +#[cfg(any(feature = "std", not(no_core_net)))] +parse_socket_impl! { + net::SocketAddrV6, "IPv6 socket address", + |(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0), +} //////////////////////////////////////////////////////////////////////////////// @@ -1550,6 +1810,7 @@ impl<'a> Visitor<'a> for PathVisitor { } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<'de: 'a, 'a> Deserialize<'de> for &'a Path { fn deserialize(deserializer: D) -> Result where @@ -1604,6 +1865,7 @@ impl<'de> Visitor<'de> for PathBufVisitor { } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<'de> Deserialize<'de> for PathBuf { fn deserialize(deserializer: D) -> Result where @@ -1613,8 +1875,11 @@ impl<'de> Deserialize<'de> for PathBuf { } } -#[cfg(all(feature = "std", de_boxed_path))] -forwarded_impl!((), Box, PathBuf::into_boxed_path); +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (), Box, PathBuf::into_boxed_path +} //////////////////////////////////////////////////////////////////////////////// @@ -1647,7 +1912,7 @@ impl<'de> Visitor<'de> for OsStringVisitor { { use std::os::unix::ffi::OsStringExt; - match try!(data.variant()) { + match tri!(data.variant()) { (OsStringKind::Unix, v) => v.newtype_variant().map(OsString::from_vec), (OsStringKind::Windows, _) => Err(Error::custom( "cannot deserialize Windows OS string on Unix", @@ -1662,7 +1927,7 @@ impl<'de> Visitor<'de> for OsStringVisitor { { use std::os::windows::ffi::OsStringExt; - match try!(data.variant()) { + match tri!(data.variant()) { (OsStringKind::Windows, v) => v .newtype_variant::>() .map(|vec| OsString::from_wide(&vec)), @@ -1674,6 +1939,7 @@ impl<'de> Visitor<'de> for OsStringVisitor { } #[cfg(all(feature = "std", any(unix, windows)))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))] impl<'de> Deserialize<'de> for OsString { fn deserialize(deserializer: D) -> Result where @@ -1685,51 +1951,35 @@ impl<'de> Deserialize<'de> for OsString { //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(feature = "std", feature = "alloc"))] -forwarded_impl!((T), Box, Box::new); - -#[cfg(any(feature = "std", feature = "alloc"))] -forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice); +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (T), Box, Box::new +} -#[cfg(any(feature = "std", feature = "alloc"))] -forwarded_impl!((), Box, String::into_boxed_str); +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (T), Box<[T]>, Vec::into_boxed_slice +} -#[cfg(all( - not(de_rc_dst), - feature = "rc", - any(feature = "std", feature = "alloc") -))] forwarded_impl! { - /// This impl requires the [`"rc"`] Cargo feature of Serde. - /// - /// Deserializing a data structure containing `Arc` will not attempt to - /// deduplicate `Arc` references to the same data. Every deserialized `Arc` - /// will end up with a strong count of 1. - /// - /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc - (T), Arc, Arc::new + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (), Box, String::into_boxed_str } -#[cfg(all( - not(de_rc_dst), - feature = "rc", - any(feature = "std", feature = "alloc") -))] forwarded_impl! { - /// This impl requires the [`"rc"`] Cargo feature of Serde. - /// - /// Deserializing a data structure containing `Rc` will not attempt to - /// deduplicate `Rc` references to the same data. Every deserialized `Rc` - /// will end up with a strong count of 1. - /// - /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc - (T), Rc, Rc::new + #[cfg(all(feature = "std", any(unix, windows)))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))] + (), Box, OsString::into_boxed_os_str } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T> where - T: ToOwned, + T: ?Sized + ToOwned, T::Owned: Deserialize<'de>, { #[inline] @@ -1748,7 +1998,11 @@ where /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl<'de, T: ?Sized> Deserialize<'de> for RcWeak +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) +)] +impl<'de, T> Deserialize<'de> for RcWeak where T: Deserialize<'de>, { @@ -1756,7 +2010,7 @@ where where D: Deserializer<'de>, { - try!(Option::::deserialize(deserializer)); + tri!(Option::::deserialize(deserializer)); Ok(RcWeak::new()) } } @@ -1766,7 +2020,11 @@ where /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl<'de, T: ?Sized> Deserialize<'de> for ArcWeak +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) +)] +impl<'de, T> Deserialize<'de> for ArcWeak where T: Deserialize<'de>, { @@ -1774,22 +2032,22 @@ where where D: Deserializer<'de>, { - try!(Option::::deserialize(deserializer)); + tri!(Option::::deserialize(deserializer)); Ok(ArcWeak::new()) } } //////////////////////////////////////////////////////////////////////////////// -#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] macro_rules! box_forwarded_impl { ( - $(#[doc = $doc:tt])* + $(#[$attr:meta])* $t:ident ) => { - $(#[doc = $doc])* - impl<'de, T: ?Sized> Deserialize<'de> for $t + $(#[$attr])* + impl<'de, T> Deserialize<'de> for $t where + T: ?Sized, Box: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result @@ -1802,7 +2060,6 @@ macro_rules! box_forwarded_impl { }; } -#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] box_forwarded_impl! { /// This impl requires the [`"rc"`] Cargo feature of Serde. /// @@ -1811,10 +2068,11 @@ box_forwarded_impl! { /// will end up with a strong count of 1. /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] Rc } -#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] box_forwarded_impl! { /// This impl requires the [`"rc"`] Cargo feature of Serde. /// @@ -1823,6 +2081,8 @@ box_forwarded_impl! { /// will end up with a strong count of 1. /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] Arc } @@ -1840,13 +2100,21 @@ where } } -forwarded_impl!((T), RefCell, RefCell::new); +forwarded_impl! { + (T), RefCell, RefCell::new +} -#[cfg(feature = "std")] -forwarded_impl!((T), Mutex, Mutex::new); +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), Mutex, Mutex::new +} -#[cfg(feature = "std")] -forwarded_impl!((T), RwLock, RwLock::new); +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), RwLock, RwLock::new +} //////////////////////////////////////////////////////////////////////////////// @@ -1858,7 +2126,6 @@ forwarded_impl!((T), RwLock, RwLock::new); // secs: u64, // nanos: u32, // } -#[cfg(any(core_duration, feature = "std"))] impl<'de> Deserialize<'de> for Duration { fn deserialize(deserializer: D) -> Result where @@ -1906,8 +2173,8 @@ impl<'de> Deserialize<'de> for Duration { b"secs" => Ok(Field::Secs), b"nanos" => Ok(Field::Nanos), _ => { - let value = ::export::from_utf8_lossy(value); - Err(Error::unknown_field(&value, FIELDS)) + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) } } } @@ -1917,6 +2184,17 @@ impl<'de> Deserialize<'de> for Duration { } } + fn check_overflow(secs: u64, nanos: u32) -> Result<(), E> + where + E: Error, + { + static NANOS_PER_SEC: u32 = 1_000_000_000; + match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { + Some(_) => Ok(()), + None => Err(E::custom("overflow deserializing Duration")), + } + } + struct DurationVisitor; impl<'de> Visitor<'de> for DurationVisitor { @@ -1930,18 +2208,19 @@ impl<'de> Deserialize<'de> for Duration { where A: SeqAccess<'de>, { - let secs: u64 = match try!(seq.next_element()) { + let secs: u64 = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(0, &self)); } }; - let nanos: u32 = match try!(seq.next_element()) { + let nanos: u32 = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(1, &self)); } }; + tri!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } @@ -1951,19 +2230,19 @@ impl<'de> Deserialize<'de> for Duration { { let mut secs: Option = None; let mut nanos: Option = None; - while let Some(key) = try!(map.next_key()) { + while let Some(key) = tri!(map.next_key()) { match key { Field::Secs => { if secs.is_some() { return Err(::duplicate_field("secs")); } - secs = Some(try!(map.next_value())); + secs = Some(tri!(map.next_value())); } Field::Nanos => { if nanos.is_some() { return Err(::duplicate_field("nanos")); } - nanos = Some(try!(map.next_value())); + nanos = Some(tri!(map.next_value())); } } } @@ -1975,11 +2254,12 @@ impl<'de> Deserialize<'de> for Duration { Some(nanos) => nanos, None => return Err(::missing_field("nanos")), }; + tri!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } } - const FIELDS: &'static [&'static str] = &["secs", "nanos"]; + const FIELDS: &[&str] = &["secs", "nanos"]; deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor) } } @@ -1987,6 +2267,7 @@ impl<'de> Deserialize<'de> for Duration { //////////////////////////////////////////////////////////////////////////////// #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<'de> Deserialize<'de> for SystemTime { fn deserialize(deserializer: D) -> Result where @@ -2042,6 +2323,17 @@ impl<'de> Deserialize<'de> for SystemTime { } } + fn check_overflow(secs: u64, nanos: u32) -> Result<(), E> + where + E: Error, + { + static NANOS_PER_SEC: u32 = 1_000_000_000; + match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { + Some(_) => Ok(()), + None => Err(E::custom("overflow deserializing SystemTime epoch offset")), + } + } + struct DurationVisitor; impl<'de> Visitor<'de> for DurationVisitor { @@ -2055,18 +2347,19 @@ impl<'de> Deserialize<'de> for SystemTime { where A: SeqAccess<'de>, { - let secs: u64 = match try!(seq.next_element()) { + let secs: u64 = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(0, &self)); } }; - let nanos: u32 = match try!(seq.next_element()) { + let nanos: u32 = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(1, &self)); } }; + tri!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } @@ -2076,7 +2369,7 @@ impl<'de> Deserialize<'de> for SystemTime { { let mut secs: Option = None; let mut nanos: Option = None; - while let Some(key) = try!(map.next_key()) { + while let Some(key) = tri!(map.next_key()) { match key { Field::Secs => { if secs.is_some() { @@ -2084,7 +2377,7 @@ impl<'de> Deserialize<'de> for SystemTime { "secs_since_epoch", )); } - secs = Some(try!(map.next_value())); + secs = Some(tri!(map.next_value())); } Field::Nanos => { if nanos.is_some() { @@ -2092,7 +2385,7 @@ impl<'de> Deserialize<'de> for SystemTime { "nanos_since_epoch", )); } - nanos = Some(try!(map.next_value())); + nanos = Some(tri!(map.next_value())); } } } @@ -2104,13 +2397,16 @@ impl<'de> Deserialize<'de> for SystemTime { Some(nanos) => nanos, None => return Err(::missing_field("nanos_since_epoch")), }; + tri!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } } - const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"]; - let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor)); - Ok(UNIX_EPOCH + duration) + const FIELDS: &[&str] = &["secs_since_epoch", "nanos_since_epoch"]; + let duration = tri!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor)); + UNIX_EPOCH + .checked_add(duration) + .ok_or_else(|| D::Error::custom("overflow deserializing SystemTime")) } } @@ -2120,9 +2416,9 @@ impl<'de> Deserialize<'de> for SystemTime { // // #[derive(Deserialize)] // #[serde(deny_unknown_fields)] -// struct Range { -// start: u64, -// end: u32, +// struct Range { +// start: Idx, +// end: Idx, // } impl<'de, Idx> Deserialize<'de> for Range where @@ -2132,19 +2428,18 @@ where where D: Deserializer<'de>, { - let (start, end) = deserializer.deserialize_struct( + let (start, end) = tri!(deserializer.deserialize_struct( "Range", range::FIELDS, range::RangeVisitor { expecting: "struct Range", phantom: PhantomData, }, - )?; + )); Ok(start..end) } } -#[cfg(range_inclusive)] impl<'de, Idx> Deserialize<'de> for RangeInclusive where Idx: Deserialize<'de>, @@ -2153,24 +2448,25 @@ where where D: Deserializer<'de>, { - let (start, end) = deserializer.deserialize_struct( + let (start, end) = tri!(deserializer.deserialize_struct( "RangeInclusive", range::FIELDS, range::RangeVisitor { expecting: "struct RangeInclusive", phantom: PhantomData, }, - )?; + )); Ok(RangeInclusive::new(start, end)) } } mod range { - use lib::*; + use crate::lib::*; - use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::private; - pub const FIELDS: &'static [&'static str] = &["start", "end"]; + pub const FIELDS: &[&str] = &["start", "end"]; // If this were outside of the serde crate, it would just use: // @@ -2214,8 +2510,8 @@ mod range { b"start" => Ok(Field::Start), b"end" => Ok(Field::End), _ => { - let value = ::export::from_utf8_lossy(value); - Err(Error::unknown_field(&value, FIELDS)) + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) } } } @@ -2244,13 +2540,13 @@ mod range { where A: SeqAccess<'de>, { - let start: Idx = match try!(seq.next_element()) { + let start: Idx = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(0, &self)); } }; - let end: Idx = match try!(seq.next_element()) { + let end: Idx = match tri!(seq.next_element()) { Some(value) => value, None => { return Err(Error::invalid_length(1, &self)); @@ -2265,19 +2561,19 @@ mod range { { let mut start: Option = None; let mut end: Option = None; - while let Some(key) = try!(map.next_key()) { + while let Some(key) = tri!(map.next_key()) { match key { Field::Start => { if start.is_some() { return Err(::duplicate_field("start")); } - start = Some(try!(map.next_value())); + start = Some(tri!(map.next_value())); } Field::End => { if end.is_some() { return Err(::duplicate_field("end")); } - end = Some(try!(map.next_value())); + end = Some(tri!(map.next_value())); } } } @@ -2296,7 +2592,284 @@ mod range { //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(ops_bound, collections_bound))] +// Similar to: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct RangeFrom { +// start: Idx, +// } +impl<'de, Idx> Deserialize<'de> for RangeFrom +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let start = tri!(deserializer.deserialize_struct( + "RangeFrom", + range_from::FIELDS, + range_from::RangeFromVisitor { + expecting: "struct RangeFrom", + phantom: PhantomData, + }, + )); + Ok(start..) + } +} + +mod range_from { + use crate::lib::*; + + use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::private; + + pub const FIELDS: &[&str] = &["start"]; + + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Start, + } + + impl<'de> Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`start`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "start" => Ok(Field::Start), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"start" => Ok(Field::Start), + _ => { + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + pub struct RangeFromVisitor { + pub expecting: &'static str, + pub phantom: PhantomData, + } + + impl<'de, Idx> Visitor<'de> for RangeFromVisitor + where + Idx: Deserialize<'de>, + { + type Value = Idx; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expecting) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let start: Idx = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + Ok(start) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut start: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::Start => { + if start.is_some() { + return Err(::duplicate_field("start")); + } + start = Some(tri!(map.next_value())); + } + } + } + let start = match start { + Some(start) => start, + None => return Err(::missing_field("start")), + }; + Ok(start) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Similar to: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct RangeTo { +// end: Idx, +// } +impl<'de, Idx> Deserialize<'de> for RangeTo +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let end = tri!(deserializer.deserialize_struct( + "RangeTo", + range_to::FIELDS, + range_to::RangeToVisitor { + expecting: "struct RangeTo", + phantom: PhantomData, + }, + )); + Ok(..end) + } +} + +mod range_to { + use crate::lib::*; + + use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::private; + + pub const FIELDS: &[&str] = &["end"]; + + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + End, + } + + impl<'de> Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`end`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "end" => Ok(Field::End), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"end" => Ok(Field::End), + _ => { + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + pub struct RangeToVisitor { + pub expecting: &'static str, + pub phantom: PhantomData, + } + + impl<'de, Idx> Visitor<'de> for RangeToVisitor + where + Idx: Deserialize<'de>, + { + type Value = Idx; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expecting) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let end: Idx = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + Ok(end) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut end: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::End => { + if end.is_some() { + return Err(::duplicate_field("end")); + } + end = Some(tri!(map.next_value())); + } + } + } + let end = match end { + Some(end) => end, + None => return Err(::missing_field("end")), + }; + Ok(end) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + impl<'de, T> Deserialize<'de> for Bound where T: Deserialize<'de>, @@ -2388,7 +2961,7 @@ where where A: EnumAccess<'de>, { - match try!(data.variant()) { + match tri!(data.variant()) { (Field::Unbounded, v) => v.unit_variant().map(|()| Bound::Unbounded), (Field::Included, v) => v.newtype_variant().map(Bound::Included), (Field::Excluded, v) => v.newtype_variant().map(Bound::Excluded), @@ -2396,7 +2969,7 @@ where } } - const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"]; + const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"]; deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData)) } @@ -2404,58 +2977,8 @@ where //////////////////////////////////////////////////////////////////////////////// -macro_rules! nonzero_integers { - ( $( $T: ident, )+ ) => { - $( - #[cfg(num_nonzero)] - impl<'de> Deserialize<'de> for num::$T { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value = try!(Deserialize::deserialize(deserializer)); - match ::new(value) { - Some(nonzero) => Ok(nonzero), - None => Err(Error::custom("expected a non-zero value")), - } - } - } - )+ - }; -} - -nonzero_integers! { - NonZeroU8, - NonZeroU16, - NonZeroU32, - NonZeroU64, - 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 -// additional `#[cfg]` -serde_if_integer128! { - nonzero_integers! { - NonZeroU128, - } - - #[cfg(num_nonzero_signed)] - nonzero_integers! { - NonZeroI128, - } -} - -//////////////////////////////////////////////////////////////////////////////// - +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] impl<'de, T, E> Deserialize<'de> for Result where T: Deserialize<'de>, @@ -2549,14 +3072,14 @@ where where A: EnumAccess<'de>, { - match try!(data.variant()) { + match tri!(data.variant()) { (Field::Ok, v) => v.newtype_variant().map(Ok), (Field::Err, v) => v.newtype_variant().map(Err), } } } - const VARIANTS: &'static [&'static str] = &["Ok", "Err"]; + const VARIANTS: &[&str] = &["Ok", "Err"]; deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData)) } @@ -2576,10 +3099,12 @@ where } } -#[cfg(all(feature = "std", std_atomic))] +#[cfg(all(feature = "std", not(no_std_atomic)))] macro_rules! atomic_impl { - ($($ty:ident)*) => { + ($($ty:ident $size:expr)*) => { $( + #[cfg(any(no_target_has_atomic, target_has_atomic = $size))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))] impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where @@ -2592,14 +3117,57 @@ macro_rules! atomic_impl { }; } -#[cfg(all(feature = "std", std_atomic))] +#[cfg(all(feature = "std", not(no_std_atomic)))] atomic_impl! { - AtomicBool - AtomicI8 AtomicI16 AtomicI32 AtomicIsize - AtomicU8 AtomicU16 AtomicU32 AtomicUsize + AtomicBool "8" + AtomicI8 "8" + AtomicI16 "16" + AtomicI32 "32" + AtomicIsize "ptr" + AtomicU8 "8" + AtomicU16 "16" + AtomicU32 "32" + AtomicUsize "ptr" +} + +#[cfg(all(feature = "std", not(no_std_atomic64)))] +atomic_impl! { + AtomicI64 "64" + AtomicU64 "64" } -#[cfg(all(feature = "std", std_atomic64))] -atomic_impl! { - AtomicI64 AtomicU64 +#[cfg(any(feature = "std", not(no_core_net)))] +struct FromStrVisitor { + expecting: &'static str, + ty: PhantomData, +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl FromStrVisitor { + fn new(expecting: &'static str) -> Self { + FromStrVisitor { + expecting, + ty: PhantomData, + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl<'de, T> Visitor<'de> for FromStrVisitor +where + T: str::FromStr, + T::Err: fmt::Display, +{ + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expecting) + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + s.parse().map_err(Error::custom) + } } diff --git a/serde/src/de/mod.rs b/serde_core/src/de/mod.rs similarity index 88% rename from serde/src/de/mod.rs rename to serde_core/src/de/mod.rs index 6d3947363..2518ae682 100644 --- a/serde/src/de/mod.rs +++ b/serde_core/src/de/mod.rs @@ -30,7 +30,7 @@ //! # The Deserializer trait //! //! [`Deserializer`] implementations are provided by third-party crates, for -//! example [`serde_json`], [`serde_yaml`] and [`bincode`]. +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. //! //! A partial list of well-maintained formats is given on the [Serde //! website][data formats]. @@ -64,8 +64,8 @@ //! - RefCell\ //! - Mutex\ //! - RwLock\ -//! - Rc\ *(if* features = ["rc"] *is enabled)* -//! - Arc\ *(if* features = ["rc"] *is enabled)* +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* //! - **Collection types**: //! - BTreeMap\ //! - BTreeSet\ @@ -101,10 +101,10 @@ //! - SocketAddrV6 //! //! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html -//! [`Deserialize`]: ../trait.Deserialize.html -//! [`Deserializer`]: ../trait.Deserializer.html +//! [`Deserialize`]: crate::Deserialize +//! [`Deserializer`]: crate::Deserializer //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html -//! [`bincode`]: https://github.com/servo/bincode +//! [`postcard`]: https://github.com/jamesmunns/postcard //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json @@ -112,25 +112,25 @@ //! [derive section of the manual]: https://serde.rs/derive.html //! [data formats]: https://serde.rs/#data-formats -use lib::*; +use crate::lib::*; //////////////////////////////////////////////////////////////////////////////// pub mod value; -mod from_primitive; mod ignored_any; mod impls; -mod utf8; pub use self::ignored_any::IgnoredAny; - +#[cfg(all(not(feature = "std"), no_core_error))] +#[doc(no_inline)] +pub use crate::std_error::Error as StdError; +#[cfg(not(any(feature = "std", no_core_error)))] +#[doc(no_inline)] +pub use core::error::Error as StdError; #[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; //////////////////////////////////////////////////////////////////////////////// @@ -156,12 +156,18 @@ macro_rules! declare_error_trait { /// type appropriate for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html + #[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::Error` is not satisfied", + ) + )] pub trait Error: Sized $(+ $($supertrait)::+)* { /// Raised when there is general error when deserializing a type. /// /// The message should not be capitalized and should not end with a period. /// - /// ```edition2018 + /// ```edition2021 /// # use std::str::FromStr; /// # /// # struct IpAddr; @@ -204,7 +210,7 @@ macro_rules! declare_error_trait { /// containing an integer, the unexpected type is the integer and the /// expected type is the string. #[cold] - fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self { + fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self { Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) } @@ -222,7 +228,7 @@ macro_rules! declare_error_trait { /// that is not valid UTF-8, the unexpected value is the bytes and the /// expected value is a string. #[cold] - fn invalid_value(unexp: Unexpected, exp: &Expected) -> Self { + fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self { Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp)) } @@ -236,7 +242,7 @@ macro_rules! declare_error_trait { /// expected. For example `exp` might say that a tuple of size 6 was /// expected. #[cold] - fn invalid_length(len: usize, exp: &Expected) -> Self { + fn invalid_length(len: usize, exp: &dyn Expected) -> Self { Error::custom(format_args!("invalid length {}, expected {}", len, exp)) } @@ -306,7 +312,7 @@ declare_error_trait!(Error: Sized + Debug + Display); /// This is used as an argument to the `invalid_type`, `invalid_value`, and /// `invalid_length` methods of the `Error` trait to build error messages. /// -/// ```edition2018 +/// ```edition2021 /// # use std::fmt; /// # /// # use serde::de::{self, Unexpected, Visitor}; @@ -393,26 +399,26 @@ pub enum Unexpected<'a> { } impl<'a> fmt::Display for Unexpected<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { use self::Unexpected::*; match *self { Bool(b) => write!(formatter, "boolean `{}`", b), Unsigned(i) => write!(formatter, "integer `{}`", i), Signed(i) => write!(formatter, "integer `{}`", i), - Float(f) => write!(formatter, "floating point `{}`", f), + Float(f) => write!(formatter, "floating point `{}`", WithDecimalPoint(f)), Char(c) => write!(formatter, "character `{}`", c), Str(s) => write!(formatter, "string {:?}", s), - Bytes(_) => write!(formatter, "byte array"), - Unit => write!(formatter, "unit value"), - Option => write!(formatter, "Option value"), - NewtypeStruct => write!(formatter, "newtype struct"), - Seq => write!(formatter, "sequence"), - Map => write!(formatter, "map"), - Enum => write!(formatter, "enum"), - UnitVariant => write!(formatter, "unit variant"), - NewtypeVariant => write!(formatter, "newtype variant"), - TupleVariant => write!(formatter, "tuple variant"), - StructVariant => write!(formatter, "struct variant"), + Bytes(_) => formatter.write_str("byte array"), + Unit => formatter.write_str("unit value"), + Option => formatter.write_str("Option value"), + NewtypeStruct => formatter.write_str("newtype struct"), + Seq => formatter.write_str("sequence"), + Map => formatter.write_str("map"), + Enum => formatter.write_str("enum"), + UnitVariant => formatter.write_str("unit variant"), + NewtypeVariant => formatter.write_str("newtype variant"), + TupleVariant => formatter.write_str("tuple variant"), + StructVariant => formatter.write_str("struct variant"), Other(other) => formatter.write_str(other), } } @@ -431,10 +437,9 @@ impl<'a> fmt::Display for Unexpected<'a> { /// Within the context of a `Visitor` implementation, the `Visitor` itself /// (`&self`) is an implementation of this trait. /// -/// ```edition2018 -/// # use std::fmt; -/// # +/// ```edition2021 /// # use serde::de::{self, Unexpected, Visitor}; +/// # use std::fmt; /// # /// # struct Example; /// # @@ -456,7 +461,7 @@ impl<'a> fmt::Display for Unexpected<'a> { /// /// Outside of a `Visitor`, `&"..."` can be used. /// -/// ```edition2018 +/// ```edition2021 /// # use serde::de::{self, Unexpected}; /// # /// # fn example() -> Result<(), E> @@ -464,9 +469,18 @@ impl<'a> fmt::Display for Unexpected<'a> { /// # E: de::Error, /// # { /// # let v = true; -/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer")); +/// return Err(de::Error::invalid_type( +/// Unexpected::Bool(v), +/// &"a negative integer", +/// )); /// # } /// ``` +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::Expected` is not satisfied", + ) +)] pub trait Expected { /// Format an explanation of what data was being expected. Same signature as /// the `Display` and `Debug` traits. @@ -482,13 +496,13 @@ where } } -impl<'a> Expected for &'a str { +impl Expected for &str { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(self) } } -impl<'a> Display for Expected + 'a { +impl Display for dyn Expected + '_ { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { Expected::fmt(self, formatter) } @@ -500,8 +514,8 @@ impl<'a> Display for Expected + 'a { /// by Serde. /// /// Serde provides `Deserialize` implementations for many Rust primitive and -/// standard library types. The complete list is [here][de]. All of these can -/// be deserialized using Serde out of the box. +/// standard library types. The complete list is [here][crate::de]. All of these +/// can be deserialized using Serde out of the box. /// /// Additionally, Serde provides a procedural macro called `serde_derive` to /// automatically generate `Deserialize` implementations for structs and enums @@ -517,7 +531,6 @@ impl<'a> Display for Expected + 'a { /// `LinkedHashMap` type that is deserializable by Serde because the crate /// provides an implementation of `Deserialize` for it. /// -/// [de]: https://docs.serde.rs/serde/de/index.html /// [derive]: https://serde.rs/derive.html /// [impl-deserialize]: https://serde.rs/impl-deserialize.html /// @@ -528,6 +541,16 @@ impl<'a> Display for Expected + 'a { /// deserializer lifetimes] for a more detailed explanation of these lifetimes. /// /// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + // Prevents `serde_core::de::Deserialize` appearing in the error message + // in projects with no direct dependency on serde_core. + message = "the trait bound `{Self}: serde::Deserialize<'de>` is not satisfied", + note = "for local types consider adding `#[derive(serde::Deserialize)]` to your `{Self}` type", + note = "for types from other crates check whether the crate offers a `serde` feature flag", + ) +)] pub trait Deserialize<'de>: Sized { /// Deserialize this value from the given Serde deserializer. /// @@ -564,7 +587,7 @@ pub trait Deserialize<'de>: Sized { D: Deserializer<'de>, { // Default implementation just delegates to `deserialize` impl. - *place = Deserialize::deserialize(deserializer)?; + *place = tri!(Deserialize::deserialize(deserializer)); Ok(()) } } @@ -577,7 +600,7 @@ pub trait Deserialize<'de>: Sized { /// from the input string, but a `from_reader` function may only deserialize /// owned data. /// -/// ```edition2018 +/// ```edition2021 /// # use serde::de::{Deserialize, DeserializeOwned}; /// # use std::io::{Read, Result}; /// # @@ -600,6 +623,12 @@ pub trait Deserialize<'de>: Sized { /// lifetimes]. /// /// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::DeserializeOwned` is not satisfied", + ) +)] pub trait DeserializeOwned: for<'de> Deserialize<'de> {} impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} @@ -616,7 +645,7 @@ impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} /// /// The canonical API for stateless deserialization looks like this: /// -/// ```edition2018 +/// ```edition2021 /// # use serde::Deserialize; /// # /// # enum Error {} @@ -630,7 +659,7 @@ impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} /// Adjusting an API like this to support stateful deserialization is a matter /// of accepting a seed as input: /// -/// ```edition2018 +/// ```edition2021 /// # use serde::de::DeserializeSeed; /// # /// # enum Error {} @@ -663,12 +692,11 @@ impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} /// into it. This requires stateful deserialization using the `DeserializeSeed` /// trait. /// -/// ```edition2018 +/// ```edition2021 +/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; /// use std::fmt; /// use std::marker::PhantomData; /// -/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; -/// /// // A DeserializeSeed implementation that uses stateful deserialization to /// // append array elements onto the end of an existing vector. The preexisting /// // state ("seed") in this case is the Vec. The `deserialize` method of @@ -707,6 +735,11 @@ impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} /// where /// A: SeqAccess<'de>, /// { +/// // Decrease the number of reallocations if there are many elements +/// if let Some(size_hint) = seq.size_hint() { +/// self.0.reserve(size_hint); +/// } +/// /// // Visit each element in the inner array and push it onto /// // the existing vector. /// while let Some(elem) = seq.next_element()? { @@ -761,6 +794,12 @@ impl DeserializeOwned for T where T: for<'de> Deserialize<'de> {} /// # Ok(()) /// # } /// ``` +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::DeserializeSeed<'de>` is not satisfied", + ) +)] pub trait DeserializeSeed<'de>: Sized { /// The type produced by using this seed. type Value; @@ -856,10 +895,10 @@ where /// The `Deserializer` trait supports two entry point styles which enables /// different kinds of deserialization. /// -/// 1. The `deserialize` method. Self-describing data formats like JSON are able -/// to look at the serialized data and tell what it represents. For example -/// the JSON deserializer may see an opening curly brace (`{`) and know that -/// it is seeing a map. If the data format supports +/// 1. The `deserialize_any` method. Self-describing data formats like JSON are +/// able to look at the serialized data and tell what it represents. For +/// example the JSON deserializer may see an opening curly brace (`{`) and +/// know that it is seeing a map. If the data format supports /// `Deserializer::deserialize_any`, it will drive the Visitor using whatever /// type it sees in the input. JSON uses this approach when deserializing /// `serde_json::Value` which is an enum that can represent any JSON @@ -868,7 +907,7 @@ where /// `Deserializer::deserialize_any`. /// /// 2. The various `deserialize_*` methods. Non-self-describing formats like -/// Bincode need to be told what is in the input in order to deserialize it. +/// Postcard need to be told what is in the input in order to deserialize it. /// The `deserialize_*` methods are hints to the deserializer for how to /// interpret the next piece of input. Non-self-describing formats are not /// able to deserialize something like `serde_json::Value` which relies on @@ -878,7 +917,7 @@ where /// `Deserializer::deserialize_any` unless you need to be told by the /// Deserializer what type is in the input. Know that relying on /// `Deserializer::deserialize_any` means your data type will be able to -/// deserialize from self-describing formats only, ruling out Bincode and many +/// deserialize from self-describing formats only, ruling out Postcard and many /// others. /// /// [Serde data model]: https://serde.rs/data-model.html @@ -897,6 +936,12 @@ where /// a basic JSON `Deserializer`. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::Deserializer<'de>` is not satisfied", + ) +)] pub trait Deserializer<'de>: Sized { /// The error type that can be returned if some error occurs during /// deserialization. @@ -909,7 +954,7 @@ pub trait Deserializer<'de>: Sized { /// `Deserializer::deserialize_any` unless you need to be told by the /// Deserializer what type is in the input. Know that relying on /// `Deserializer::deserialize_any` means your data type will be able to - /// deserialize from self-describing formats only, ruling out Bincode and + /// deserialize from self-describing formats only, ruling out Postcard and /// many others. fn deserialize_any(self, visitor: V) -> Result where @@ -940,18 +985,15 @@ pub trait Deserializer<'de>: Sized { where V: Visitor<'de>; - serde_if_integer128! { - /// Hint that the `Deserialize` type is expecting an `i128` value. - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default behavior unconditionally returns an error. - fn deserialize_i128(self, visitor: V) -> Result - where - V: Visitor<'de> - { - let _ = visitor; - Err(Error::custom("i128 is not supported")) - } + /// Hint that the `Deserialize` type is expecting an `i128` value. + /// + /// The default behavior unconditionally returns an error. + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let _ = visitor; + Err(Error::custom("i128 is not supported")) } /// Hint that the `Deserialize` type is expecting a `u8` value. @@ -974,18 +1016,15 @@ pub trait Deserializer<'de>: Sized { where V: Visitor<'de>; - serde_if_integer128! { - /// Hint that the `Deserialize` type is expecting an `u128` value. - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default behavior unconditionally returns an error. - fn deserialize_u128(self, visitor: V) -> Result - where - V: Visitor<'de> - { - let _ = visitor; - Err(Error::custom("u128 is not supported")) - } + /// Hint that the `Deserialize` type is expecting an `u128` value. + /// + /// The default behavior unconditionally returns an error. + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let _ = visitor; + Err(Error::custom("u128 is not supported")) } /// Hint that the `Deserialize` type is expecting a `f32` value. @@ -1008,7 +1047,7 @@ pub trait Deserializer<'de>: Sized { /// `Deserializer`. /// /// If the `Visitor` would benefit from taking ownership of `String` data, - /// indiciate this to the `Deserializer` by using `deserialize_string` + /// indicate this to the `Deserializer` by using `deserialize_string` /// instead. fn deserialize_str(self, visitor: V) -> Result where @@ -1150,10 +1189,10 @@ pub trait Deserializer<'de>: Sized { /// Some types have a human-readable form that may be somewhat expensive to /// construct, as well as a binary form that is compact and efficient. /// Generally text-based formats like JSON and YAML will prefer to use the - /// human-readable one and binary formats like Bincode will prefer the + /// human-readable one and binary formats like Postcard will prefer the /// compact one. /// - /// ```edition2018 + /// ```edition2021 /// # use std::ops::Add; /// # use std::str::FromStr; /// # @@ -1214,6 +1253,16 @@ pub trait Deserializer<'de>: Sized { fn is_human_readable(&self) -> bool { true } + + // Not public API. + #[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))] + #[doc(hidden)] + fn __deserialize_content_v1(self, visitor: V) -> Result + where + V: Visitor<'de, Value = crate::private::Content<'de>>, + { + self.deserialize_any(visitor) + } } //////////////////////////////////////////////////////////////////////////////// @@ -1230,10 +1279,9 @@ pub trait Deserializer<'de>: Sized { /// /// # Example /// -/// ```edition2018 -/// # use std::fmt; -/// # +/// ```edition2021 /// # use serde::de::{self, Unexpected, Visitor}; +/// # use std::fmt; /// # /// /// A visitor that deserializes a long string - a string containing at least /// /// some minimum number of bytes. @@ -1260,6 +1308,12 @@ pub trait Deserializer<'de>: Sized { /// } /// } /// ``` +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::Visitor<'de>` is not satisfied", + ) +)] pub trait Visitor<'de>: Sized { /// The value produced by this visitor. type Value; @@ -1271,7 +1325,7 @@ pub trait Visitor<'de>: Sized { /// "an integer between 0 and 64". The message should not be capitalized and /// should not end with a period. /// - /// ```edition2018 + /// ```edition2021 /// # use std::fmt; /// # /// # struct S { @@ -1344,18 +1398,20 @@ pub trait Visitor<'de>: Sized { Err(Error::invalid_type(Unexpected::Signed(v), &self)) } - serde_if_integer128! { - /// The input contains a `i128`. - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default implementation fails with a type error. - fn visit_i128(self, v: i128) -> Result - where - E: Error, - { - let _ = v; - Err(Error::invalid_type(Unexpected::Other("i128"), &self)) - } + /// The input contains a `i128`. + /// + /// The default implementation fails with a type error. + fn visit_i128(self, v: i128) -> Result + where + E: Error, + { + let mut buf = [0u8; 58]; + let mut writer = crate::format::Buf::new(&mut buf); + fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap(); + Err(Error::invalid_type( + Unexpected::Other(writer.as_str()), + &self, + )) } /// The input contains a `u8`. @@ -1404,18 +1460,20 @@ pub trait Visitor<'de>: Sized { Err(Error::invalid_type(Unexpected::Unsigned(v), &self)) } - serde_if_integer128! { - /// The input contains a `u128`. - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default implementation fails with a type error. - fn visit_u128(self, v: u128) -> Result - where - E: Error, - { - let _ = v; - Err(Error::invalid_type(Unexpected::Other("u128"), &self)) - } + /// The input contains a `u128`. + /// + /// The default implementation fails with a type error. + fn visit_u128(self, v: u128) -> Result + where + E: Error, + { + let mut buf = [0u8; 57]; + let mut writer = crate::format::Buf::new(&mut buf); + fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap(); + Err(Error::invalid_type( + Unexpected::Other(writer.as_str()), + &self, + )) } /// The input contains an `f32`. @@ -1451,7 +1509,7 @@ pub trait Visitor<'de>: Sized { where E: Error, { - self.visit_str(utf8::encode(v).as_str()) + self.visit_str(v.encode_utf8(&mut [0u8; 4])) } /// The input contains a string. The lifetime of the string is ephemeral and @@ -1506,6 +1564,7 @@ pub trait Visitor<'de>: Sized { /// `String`. #[inline] #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] fn visit_string(self, v: String) -> Result where E: Error, @@ -1528,7 +1587,6 @@ pub trait Visitor<'de>: Sized { where E: Error, { - let _ = v; Err(Error::invalid_type(Unexpected::Bytes(v), &self)) } @@ -1536,7 +1594,7 @@ pub trait Visitor<'de>: Sized { /// `Deserializer`. /// /// This enables zero-copy deserialization of bytes in some formats. For - /// example Bincode data containing bytes can be deserialized with zero + /// example Postcard data containing bytes can be deserialized with zero /// copying into a `&'a [u8]` as long as the input data outlives `'a`. /// /// The default implementation forwards to `visit_bytes`. @@ -1565,6 +1623,7 @@ pub trait Visitor<'de>: Sized { /// The default implementation forwards to `visit_bytes` and then drops the /// `Vec`. #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] fn visit_byte_buf(self, v: Vec) -> Result where E: Error, @@ -1681,6 +1740,12 @@ pub trait Visitor<'de>: Sized { /// implementation of `SeqAccess` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::SeqAccess<'de>` is not satisfied", + ) +)] pub trait SeqAccess<'de> { /// The error type that can be returned if some error occurs during /// deserialization. @@ -1715,9 +1780,9 @@ pub trait SeqAccess<'de> { } } -impl<'de, 'a, A> SeqAccess<'de> for &'a mut A +impl<'de, A> SeqAccess<'de> for &mut A where - A: SeqAccess<'de>, + A: ?Sized + SeqAccess<'de>, { type Error = A::Error; @@ -1763,6 +1828,12 @@ where /// implementation of `MapAccess` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::MapAccess<'de>` is not satisfied", + ) +)] pub trait MapAccess<'de> { /// The error type that can be returned if some error occurs during /// deserialization. @@ -1808,9 +1879,9 @@ pub trait MapAccess<'de> { K: DeserializeSeed<'de>, V: DeserializeSeed<'de>, { - match try!(self.next_key_seed(kseed)) { + match tri!(self.next_key_seed(kseed)) { Some(key) => { - let value = try!(self.next_value_seed(vseed)); + let value = tri!(self.next_value_seed(vseed)); Ok(Some((key, value))) } None => Ok(None), @@ -1868,9 +1939,9 @@ pub trait MapAccess<'de> { } } -impl<'de, 'a, A> MapAccess<'de> for &'a mut A +impl<'de, A> MapAccess<'de> for &mut A where - A: MapAccess<'de>, + A: ?Sized + MapAccess<'de>, { type Error = A::Error; @@ -1955,6 +2026,12 @@ where /// implementation of `EnumAccess` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::EnumAccess<'de>` is not satisfied", + ) +)] pub trait EnumAccess<'de>: Sized { /// The error type that can be returned if some error occurs during /// deserialization. @@ -2002,6 +2079,12 @@ pub trait EnumAccess<'de>: Sized { /// implementation of `VariantAccess` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::de::VariantAccess<'de>` is not satisfied", + ) +)] pub trait VariantAccess<'de>: Sized { /// The error type that can be returned if some error occurs during /// deserialization. Must match the error type of our `EnumAccess`. @@ -2012,7 +2095,7 @@ pub trait VariantAccess<'de>: Sized { /// If the data contains a different type of variant, the following /// `invalid_type` error should be constructed: /// - /// ```edition2018 + /// ```edition2021 /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # /// # struct X; @@ -2052,7 +2135,7 @@ pub trait VariantAccess<'de>: Sized { /// If the data contains a different type of variant, the following /// `invalid_type` error should be constructed: /// - /// ```edition2018 + /// ```edition2021 /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # /// # struct X; @@ -2108,7 +2191,7 @@ pub trait VariantAccess<'de>: Sized { /// If the data contains a different type of variant, the following /// `invalid_type` error should be constructed: /// - /// ```edition2018 + /// ```edition2021 /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # /// # struct X; @@ -2125,11 +2208,7 @@ pub trait VariantAccess<'de>: Sized { /// # T: DeserializeSeed<'de>, /// # { unimplemented!() } /// # - /// fn tuple_variant( - /// self, - /// _len: usize, - /// _visitor: V, - /// ) -> Result + /// fn tuple_variant(self, _len: usize, _visitor: V) -> Result /// where /// V: Visitor<'de>, /// { @@ -2155,7 +2234,7 @@ pub trait VariantAccess<'de>: Sized { /// If the data contains a different type of variant, the following /// `invalid_type` error should be constructed: /// - /// ```edition2018 + /// ```edition2021 /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; /// # /// # struct X; @@ -2215,10 +2294,10 @@ pub trait VariantAccess<'de>: Sized { /// /// # Example /// -/// ```edition2018 +/// ```edition2021 +/// use serde::de::{value, Deserialize, IntoDeserializer}; +/// use serde_derive::Deserialize; /// use std::str::FromStr; -/// use serde::Deserialize; -/// use serde::de::{value, IntoDeserializer}; /// /// #[derive(Deserialize)] /// enum Setting { @@ -2262,15 +2341,52 @@ impl Display for OneOf { 1 => write!(formatter, "`{}`", self.names[0]), 2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]), _ => { - try!(write!(formatter, "one of ")); + tri!(formatter.write_str("one of ")); for (i, alt) in self.names.iter().enumerate() { if i > 0 { - try!(write!(formatter, ", ")); + tri!(formatter.write_str(", ")); } - try!(write!(formatter, "`{}`", alt)); + tri!(write!(formatter, "`{}`", alt)); } Ok(()) } } } } + +struct WithDecimalPoint(f64); + +impl Display for WithDecimalPoint { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + struct LookForDecimalPoint<'f, 'a> { + formatter: &'f mut fmt::Formatter<'a>, + has_decimal_point: bool, + } + + impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> { + fn write_str(&mut self, fragment: &str) -> fmt::Result { + self.has_decimal_point |= fragment.contains('.'); + self.formatter.write_str(fragment) + } + + fn write_char(&mut self, ch: char) -> fmt::Result { + self.has_decimal_point |= ch == '.'; + self.formatter.write_char(ch) + } + } + + if self.0.is_finite() { + let mut writer = LookForDecimalPoint { + formatter, + has_decimal_point: false, + }; + tri!(write!(writer, "{}", self.0)); + if !writer.has_decimal_point { + tri!(formatter.write_str(".0")); + } + } else { + tri!(write!(formatter, "{}", self.0)); + } + Ok(()) + } +} diff --git a/serde/src/de/value.rs b/serde_core/src/de/value.rs similarity index 75% rename from serde/src/de/value.rs rename to serde_core/src/de/value.rs index 4044f322b..3d5475def 100644 --- a/serde/src/de/value.rs +++ b/serde_core/src/de/value.rs @@ -1,10 +1,10 @@ //! Building blocks for deserializing basic values using the `IntoDeserializer` //! trait. //! -//! ```edition2018 +//! ```edition2021 +//! use serde::de::{value, Deserialize, IntoDeserializer}; +//! use serde_derive::Deserialize; //! use std::str::FromStr; -//! use serde::Deserialize; -//! use serde::de::{value, IntoDeserializer}; //! //! #[derive(Deserialize)] //! enum Setting { @@ -21,12 +21,12 @@ //! } //! ``` -use lib::*; +use crate::lib::*; use self::private::{First, Second}; -use de::{self, Expected, IntoDeserializer, SeqAccess}; -use private::de::size_hint; -use ser; +use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor}; +use crate::private::size_hint; +use crate::ser; //////////////////////////////////////////////////////////////////////////////// @@ -48,7 +48,7 @@ macro_rules! impl_copy_clone { /// A minimal representation of all possible errors that can occur using the /// `IntoDeserializer` trait. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, PartialEq)] pub struct Error { err: ErrorImpl, } @@ -93,17 +93,27 @@ impl ser::Error for Error { impl Display for Error { #[cfg(any(feature = "std", feature = "alloc"))] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(&self.err) } #[cfg(not(any(feature = "std", feature = "alloc")))] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("Serde deserialization error") } } +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut debug = formatter.debug_tuple("Error"); + #[cfg(any(feature = "std", feature = "alloc"))] + debug.field(&self.err); + debug.finish() + } +} + #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl error::Error for Error { fn description(&self) -> &str { &self.err @@ -119,20 +129,26 @@ where type Deserializer = UnitDeserializer; fn into_deserializer(self) -> UnitDeserializer { - UnitDeserializer { - marker: PhantomData, - } + UnitDeserializer::new() } } /// A deserializer holding a `()`. -#[derive(Debug)] pub struct UnitDeserializer { marker: PhantomData, } impl_copy_clone!(UnitDeserializer); +impl UnitDeserializer { + #[allow(missing_docs)] + pub fn new() -> Self { + UnitDeserializer { + marker: PhantomData, + } + } +} + impl<'de, E> de::Deserializer<'de> for UnitDeserializer where E: de::Error, @@ -160,16 +176,35 @@ where } } +impl<'de, E> IntoDeserializer<'de, E> for UnitDeserializer +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +impl Debug for UnitDeserializer { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.debug_struct("UnitDeserializer").finish() + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer that cannot be instantiated. #[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] pub struct NeverDeserializer { never: !, marker: PhantomData, } #[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl<'de, E> IntoDeserializer<'de, E> for ! where E: de::Error, @@ -202,13 +237,24 @@ where } } +#[cfg(feature = "unstable")] +impl<'de, E> IntoDeserializer<'de, E> for NeverDeserializer +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + //////////////////////////////////////////////////////////////////////////////// macro_rules! primitive_deserializer { ($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => { #[doc = "A deserializer holding"] #[doc = $doc] - #[derive(Debug)] pub struct $name { value: $ty, marker: PhantomData @@ -223,8 +269,15 @@ macro_rules! primitive_deserializer { type Deserializer = $name; fn into_deserializer(self) -> $name { + $name::new(self) + } + } + + impl $name { + #[allow(missing_docs)] + pub fn new(value: $ty) -> Self { $name { - value: self, + value, marker: PhantomData, } } @@ -249,6 +302,26 @@ macro_rules! primitive_deserializer { visitor.$method(self.value $($cast)*) } } + + impl<'de, E> IntoDeserializer<'de, E> for $name + where + E: de::Error, + { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } + } + + impl Debug for $name { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct(stringify!($name)) + .field("value", &self.value) + .finish() + } + } } } @@ -257,22 +330,18 @@ primitive_deserializer!(i8, "an `i8`.", I8Deserializer, visit_i8); primitive_deserializer!(i16, "an `i16`.", I16Deserializer, visit_i16); primitive_deserializer!(i32, "an `i32`.", I32Deserializer, visit_i32); primitive_deserializer!(i64, "an `i64`.", I64Deserializer, visit_i64); +primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128); primitive_deserializer!(isize, "an `isize`.", IsizeDeserializer, visit_i64 as i64); primitive_deserializer!(u8, "a `u8`.", U8Deserializer, visit_u8); primitive_deserializer!(u16, "a `u16`.", U16Deserializer, visit_u16); primitive_deserializer!(u64, "a `u64`.", U64Deserializer, visit_u64); +primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128); primitive_deserializer!(usize, "a `usize`.", UsizeDeserializer, visit_u64 as u64); primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32); primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64); primitive_deserializer!(char, "a `char`.", CharDeserializer, visit_char); -serde_if_integer128! { - primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128); - primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128); -} - /// A deserializer holding a `u32`. -#[derive(Debug)] pub struct U32Deserializer { value: u32, marker: PhantomData, @@ -287,8 +356,15 @@ where type Deserializer = U32Deserializer; fn into_deserializer(self) -> U32Deserializer { + U32Deserializer::new(self) + } +} + +impl U32Deserializer { + #[allow(missing_docs)] + pub fn new(value: u32) -> Self { U32Deserializer { - value: self, + value, marker: PhantomData, } } @@ -328,6 +404,17 @@ where } } +impl<'de, E> IntoDeserializer<'de, E> for U32Deserializer +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, E> de::EnumAccess<'de> for U32Deserializer where E: de::Error, @@ -343,10 +430,18 @@ where } } +impl Debug for U32Deserializer { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("U32Deserializer") + .field("value", &self.value) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer holding a `&str`. -#[derive(Debug)] pub struct StrDeserializer<'a, E> { value: &'a str, marker: PhantomData, @@ -361,8 +456,15 @@ where type Deserializer = StrDeserializer<'a, E>; fn into_deserializer(self) -> StrDeserializer<'a, E> { + StrDeserializer::new(self) + } +} + +impl<'a, E> StrDeserializer<'a, E> { + #[allow(missing_docs)] + pub fn new(value: &'a str) -> Self { StrDeserializer { - value: self, + value, marker: PhantomData, } } @@ -402,6 +504,17 @@ where } } +impl<'de, 'a, E> IntoDeserializer<'de, E> for StrDeserializer<'a, E> +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E> where E: de::Error, @@ -417,11 +530,19 @@ where } } +impl<'a, E> Debug for StrDeserializer<'a, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("StrDeserializer") + .field("value", &self.value) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer holding a `&str` with a lifetime tied to another /// deserializer. -#[derive(Debug)] pub struct BorrowedStrDeserializer<'de, E> { value: &'de str, marker: PhantomData, @@ -433,7 +554,7 @@ impl<'de, E> BorrowedStrDeserializer<'de, E> { /// Create a new borrowed deserializer from the given string. pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> { BorrowedStrDeserializer { - value: value, + value, marker: PhantomData, } } @@ -473,6 +594,17 @@ where } } +impl<'de, E> IntoDeserializer<'de, E> for BorrowedStrDeserializer<'de, E> +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E> where E: de::Error, @@ -488,11 +620,20 @@ where } } +impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("BorrowedStrDeserializer") + .field("value", &self.value) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer holding a `String`. #[cfg(any(feature = "std", feature = "alloc"))] -#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] pub struct StringDeserializer { value: String, marker: PhantomData, @@ -509,6 +650,7 @@ impl Clone for StringDeserializer { } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, E> IntoDeserializer<'de, E> for String where E: de::Error, @@ -516,8 +658,16 @@ where type Deserializer = StringDeserializer; fn into_deserializer(self) -> StringDeserializer { + StringDeserializer::new(self) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl StringDeserializer { + #[allow(missing_docs)] + pub fn new(value: String) -> Self { StringDeserializer { - value: self, + value, marker: PhantomData, } } @@ -559,7 +709,19 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'de, 'a, E> de::EnumAccess<'de> for StringDeserializer +impl<'de, E> IntoDeserializer<'de, E> for StringDeserializer +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, E> de::EnumAccess<'de> for StringDeserializer where E: de::Error, { @@ -574,11 +736,21 @@ where } } +#[cfg(any(feature = "std", feature = "alloc"))] +impl Debug for StringDeserializer { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("StringDeserializer") + .field("value", &self.value) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer holding a `Cow`. #[cfg(any(feature = "std", feature = "alloc"))] -#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] pub struct CowStrDeserializer<'a, E> { value: Cow<'a, str>, marker: PhantomData, @@ -595,6 +767,7 @@ impl<'a, E> Clone for CowStrDeserializer<'a, E> { } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str> where E: de::Error, @@ -602,8 +775,16 @@ where type Deserializer = CowStrDeserializer<'a, E>; fn into_deserializer(self) -> CowStrDeserializer<'a, E> { + CowStrDeserializer::new(self) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, E> CowStrDeserializer<'a, E> { + #[allow(missing_docs)] + pub fn new(value: Cow<'a, str>) -> Self { CowStrDeserializer { - value: self, + value, marker: PhantomData, } } @@ -647,6 +828,18 @@ where } } +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> IntoDeserializer<'de, E> for CowStrDeserializer<'a, E> +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + #[cfg(any(feature = "std", feature = "alloc"))] impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E> where @@ -663,29 +856,107 @@ where } } +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, E> Debug for CowStrDeserializer<'a, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("CowStrDeserializer") + .field("value", &self.value) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// +/// A deserializer holding a `&[u8]`. Always calls [`Visitor::visit_bytes`]. +pub struct BytesDeserializer<'a, E> { + value: &'a [u8], + marker: PhantomData, +} + +impl<'a, E> BytesDeserializer<'a, E> { + /// Create a new deserializer from the given bytes. + pub fn new(value: &'a [u8]) -> Self { + BytesDeserializer { + value, + marker: PhantomData, + } + } +} + +impl_copy_clone!(BytesDeserializer<'a>); + +impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8] +where + E: de::Error, +{ + type Deserializer = BytesDeserializer<'a, E>; + + fn into_deserializer(self) -> BytesDeserializer<'a, E> { + BytesDeserializer::new(self) + } +} + +impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_bytes(self.value) + } + + 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, 'a, E> IntoDeserializer<'de, E> for BytesDeserializer<'a, E> +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +impl<'a, E> Debug for BytesDeserializer<'a, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("BytesDeserializer") + .field("value", &self.value) + .finish() + } +} + /// A deserializer holding a `&[u8]` with a lifetime tied to another -/// deserializer. -#[derive(Debug)] +/// deserializer. Always calls [`Visitor::visit_borrowed_bytes`]. pub struct BorrowedBytesDeserializer<'de, E> { value: &'de [u8], marker: PhantomData, } -impl_copy_clone!(BorrowedBytesDeserializer<'de>); - impl<'de, E> BorrowedBytesDeserializer<'de, E> { - /// Create a new borrowed deserializer from the given byte slice. - pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> { + /// Create a new borrowed deserializer from the given borrowed bytes. + pub fn new(value: &'de [u8]) -> Self { BorrowedBytesDeserializer { - value: value, + value, marker: PhantomData, } } } -impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E> +impl_copy_clone!(BorrowedBytesDeserializer<'de>); + +impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E> where E: de::Error, { @@ -693,7 +964,7 @@ where fn deserialize_any(self, visitor: V) -> Result where - V: de::Visitor<'de>, + V: Visitor<'de>, { visitor.visit_borrowed_bytes(self.value) } @@ -701,14 +972,34 @@ where 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 identifier ignored_any enum + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de, E> IntoDeserializer<'de, E> for BorrowedBytesDeserializer<'de, E> +where + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("BorrowedBytesDeserializer") + .field("value", &self.value) + .finish() } } //////////////////////////////////////////////////////////////////////////////// /// A deserializer that iterates over a sequence. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct SeqDeserializer { iter: iter::Fuse, count: usize, @@ -763,8 +1054,8 @@ where where V: de::Visitor<'de>, { - let v = try!(visitor.visit_seq(&mut self)); - try!(self.end()); + let v = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); Ok(v) } @@ -775,6 +1066,19 @@ where } } +impl<'de, I, T, E> IntoDeserializer<'de, E> for SeqDeserializer +where + I: Iterator, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, I, T, E> de::SeqAccess<'de> for SeqDeserializer where I: Iterator, @@ -806,16 +1110,30 @@ struct ExpectedInSeq(usize); impl Expected for ExpectedInSeq { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { if self.0 == 1 { - write!(formatter, "1 element in sequence") + formatter.write_str("1 element in sequence") } else { write!(formatter, "{} elements in sequence", self.0) } } } +impl Debug for SeqDeserializer +where + I: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("SeqDeserializer") + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } +} + //////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, T, E> IntoDeserializer<'de, E> for Vec where T: IntoDeserializer<'de, E>, @@ -829,6 +1147,7 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet where T: IntoDeserializer<'de, E> + Eq + Ord, @@ -842,6 +1161,7 @@ where } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet where T: IntoDeserializer<'de, E> + Eq + Hash, @@ -866,7 +1186,7 @@ pub struct SeqAccessDeserializer { impl SeqAccessDeserializer { /// Construct a new `SeqAccessDeserializer`. pub fn new(seq: A) -> Self { - SeqAccessDeserializer { seq: seq } + SeqAccessDeserializer { seq } } } @@ -890,6 +1210,17 @@ where } } +impl<'de, A> IntoDeserializer<'de, A::Error> for SeqAccessDeserializer +where + A: de::SeqAccess<'de>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + //////////////////////////////////////////////////////////////////////////////// /// A deserializer that iterates over a map. @@ -975,8 +1306,8 @@ where where V: de::Visitor<'de>, { - let value = try!(visitor.visit_map(&mut self)); - try!(self.end()); + let value = tri!(visitor.visit_map(&mut self)); + tri!(self.end()); Ok(value) } @@ -984,8 +1315,8 @@ where where V: de::Visitor<'de>, { - let value = try!(visitor.visit_seq(&mut self)); - try!(self.end()); + let value = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); Ok(value) } @@ -1004,6 +1335,21 @@ where } } +impl<'de, I, E> IntoDeserializer<'de, E> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, I, E> de::MapAccess<'de> for MapDeserializer<'de, I, E> where I: Iterator, @@ -1049,8 +1395,8 @@ where { match self.next_pair() { Some((key, value)) => { - let key = try!(kseed.deserialize(key.into_deserializer())); - let value = try!(vseed.deserialize(value.into_deserializer())); + let key = tri!(kseed.deserialize(key.into_deserializer())); + let value = tri!(vseed.deserialize(value.into_deserializer())); Ok(Some((key, value))) } None => Ok(None), @@ -1108,7 +1454,6 @@ where } } -// Cannot #[derive(Debug)] because of the bound `Second: Debug`. impl<'de, I, E> Debug for MapDeserializer<'de, I, E> where I: Iterator + Debug, @@ -1121,8 +1466,6 @@ where .field("iter", &self.iter) .field("value", &self.value) .field("count", &self.count) - .field("lifetime", &self.lifetime) - .field("error", &self.error) .finish() } } @@ -1157,7 +1500,7 @@ where V: de::Visitor<'de>, { let mut pair_visitor = PairVisitor(Some(self.0), Some(self.1), PhantomData); - let pair = try!(visitor.visit_seq(&mut pair_visitor)); + let pair = tri!(visitor.visit_seq(&mut pair_visitor)); if pair_visitor.1.is_none() { Ok(pair) } else { @@ -1221,7 +1564,7 @@ struct ExpectedInMap(usize); impl Expected for ExpectedInMap { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { if self.0 == 1 { - write!(formatter, "1 element in map") + formatter.write_str("1 element in map") } else { write!(formatter, "{} elements in map", self.0) } @@ -1231,6 +1574,7 @@ impl Expected for ExpectedInMap { //////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap where K: IntoDeserializer<'de, E> + Eq + Ord, @@ -1245,6 +1589,7 @@ where } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap where K: IntoDeserializer<'de, E> + Eq + Hash, @@ -1270,7 +1615,7 @@ pub struct MapAccessDeserializer { impl MapAccessDeserializer { /// Construct a new `MapAccessDeserializer`. pub fn new(map: A) -> Self { - MapAccessDeserializer { map: map } + MapAccessDeserializer { map } } } @@ -1306,6 +1651,17 @@ where } } +impl<'de, A> IntoDeserializer<'de, A::Error> for MapAccessDeserializer +where + A: de::MapAccess<'de>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer where A: de::MapAccess<'de>, @@ -1317,7 +1673,7 @@ where where T: de::DeserializeSeed<'de>, { - match self.map.next_key_seed(seed)? { + match tri!(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")), } @@ -1326,12 +1682,59 @@ where //////////////////////////////////////////////////////////////////////////////// +/// A deserializer holding an `EnumAccess`. +#[derive(Clone, Debug)] +pub struct EnumAccessDeserializer { + access: A, +} + +impl EnumAccessDeserializer { + /// Construct a new `EnumAccessDeserializer`. + pub fn new(access: A) -> Self { + EnumAccessDeserializer { access } + } +} + +impl<'de, A> de::Deserializer<'de> for EnumAccessDeserializer +where + A: de::EnumAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self.access) + } + + 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, A> IntoDeserializer<'de, A::Error> for EnumAccessDeserializer +where + A: de::EnumAccess<'de>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +//////////////////////////////////////////////////////////////////////////////// + mod private { - use lib::*; + use crate::lib::*; - use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor}; + use crate::de::{ + self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor, + }; - #[derive(Clone, Debug)] pub struct UnitOnly { marker: PhantomData, } @@ -1390,13 +1793,12 @@ mod private { } } - #[derive(Clone, Debug)] pub struct MapAsEnum { map: A, } pub fn map_as_enum(map: A) -> MapAsEnum { - MapAsEnum { map: map } + MapAsEnum { map } } impl<'de, A> VariantAccess<'de> for MapAsEnum @@ -1420,10 +1822,7 @@ mod private { where V: Visitor<'de>, { - self.map.next_value_seed(SeedTupleVariant { - len: len, - visitor: visitor, - }) + self.map.next_value_seed(SeedTupleVariant { len, visitor }) } fn struct_variant( @@ -1434,8 +1833,7 @@ mod private { where V: Visitor<'de>, { - self.map - .next_value_seed(SeedStructVariant { visitor: visitor }) + self.map.next_value_seed(SeedStructVariant { visitor }) } } diff --git a/serde_core/src/format.rs b/serde_core/src/format.rs new file mode 100644 index 000000000..9053cc070 --- /dev/null +++ b/serde_core/src/format.rs @@ -0,0 +1,30 @@ +use crate::lib::fmt::{self, Write}; +use crate::lib::str; + +pub(super) struct Buf<'a> { + bytes: &'a mut [u8], + offset: usize, +} + +impl<'a> Buf<'a> { + pub fn new(bytes: &'a mut [u8]) -> Self { + Buf { bytes, offset: 0 } + } + + pub fn as_str(&self) -> &str { + let slice = &self.bytes[..self.offset]; + unsafe { str::from_utf8_unchecked(slice) } + } +} + +impl<'a> Write for Buf<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.offset + s.len() > self.bytes.len() { + Err(fmt::Error) + } else { + self.bytes[self.offset..self.offset + s.len()].copy_from_slice(s.as_bytes()); + self.offset += s.len(); + Ok(()) + } + } +} diff --git a/serde_core/src/lib.rs b/serde_core/src/lib.rs new file mode 100644 index 000000000..b2b32b50b --- /dev/null +++ b/serde_core/src/lib.rs @@ -0,0 +1,121 @@ +//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data +//! structures efficiently and generically. +//! +//! The `serde_core` crate contains Serde's trait definitions with **no support +//! for #\[derive()\]**. +//! +//! In crates that derive an implementation of `Serialize` or `Deserialize`, you +//! must depend on the [`serde`] crate, not `serde_core`. +//! +//! [`serde`]: https://crates.io/crates/serde +//! +//! In crates that handwrite implementations of Serde traits, or only use them +//! as trait bounds, depending on `serde_core` is permitted. But `serde` +//! re-exports all of these traits and can be used for this use case too. If in +//! doubt, disregard `serde_core` and always use `serde`. +//! +//! Crates that depend on `serde_core` instead of `serde` are able to compile in +//! parallel with `serde_derive` even when `serde`'s "derive" feature is turned on, +//! as shown in the following build timings. +//! +//!
+//! +//! +//! +//! +//!
When serde_json depends on serde
+//! +//!
+//! +//! +//! +//! +//!
When serde_json depends on serde_core
+ +//////////////////////////////////////////////////////////////////////////////// + +// Serde types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/serde_core/1.0.228")] +// Support using Serde without the standard library! +#![cfg_attr(not(feature = "std"), no_std)] +// Show which crate feature enables conditionally compiled APIs in documentation. +#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))] +#![cfg_attr(docsrs, allow(internal_features))] +// Unstable functionality only if the user asks for it. For tracking and +// discussion of these features please refer to this issue: +// +// https://github.com/serde-rs/serde/issues/812 +#![cfg_attr(feature = "unstable", feature(never_type))] +#![allow(unknown_lints, bare_trait_objects, deprecated)] +// Ignored clippy and clippy_pedantic lints +#![allow( + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768 + clippy::semicolon_if_nothing_returned, + // not available in our oldest supported compiler + clippy::empty_enums, + clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772 + // integer and float ser/de requires these sorts of casts + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + // things are often more readable this way + clippy::cast_lossless, + clippy::module_name_repetitions, + clippy::single_match_else, + clippy::type_complexity, + clippy::use_self, + clippy::zero_prefixed_literal, + // correctly used + clippy::derive_partial_eq_without_eq, + clippy::enum_glob_use, + clippy::explicit_auto_deref, + clippy::incompatible_msrv, + clippy::let_underscore_untyped, + clippy::map_err_ignore, + clippy::new_without_default, + clippy::result_unit_err, + clippy::wildcard_imports, + // not practical + clippy::needless_pass_by_value, + clippy::similar_names, + clippy::too_many_lines, + // preference + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::needless_lifetimes, + clippy::unseparated_literal_suffix, + // false positive + clippy::needless_doctest_main, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, +)] +// Restrictions +#![deny(clippy::question_mark_used)] +// Rustc lints. +#![deny(missing_docs, unused_imports)] + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[macro_use] +mod crate_root; +#[macro_use] +mod macros; + +crate_root!(); + +#[macro_export] +#[doc(hidden)] +macro_rules! __require_serde_not_serde_core { + () => { + ::core::compile_error!( + "Serde derive requires a dependency on the serde crate, not serde_core" + ); + }; +} diff --git a/serde/src/macros.rs b/serde_core/src/macros.rs similarity index 93% rename from serde/src/macros.rs rename to serde_core/src/macros.rs index 57600a535..b95673050 100644 --- a/serde/src/macros.rs +++ b/serde_core/src/macros.rs @@ -1,7 +1,6 @@ // Super explicit first paragraph because this shows up at the top level and // trips up people who are just looking for basic Serialize / Deserialize // documentation. -// /// Helper macro when implementing the `Deserializer` part of a new data format /// for Serde. /// @@ -11,7 +10,7 @@ /// input. This requires repetitive implementations of all the [`Deserializer`] /// trait methods. /// -/// ```edition2018 +/// ```edition2021 /// # use serde::forward_to_deserialize_any; /// # use serde::de::{value, Deserializer, Visitor}; /// # @@ -47,7 +46,7 @@ /// methods so that they forward directly to [`Deserializer::deserialize_any`]. /// You can choose which methods to forward. /// -/// ```edition2018 +/// ```edition2021 /// # use serde::forward_to_deserialize_any; /// # use serde::de::{value, Deserializer, Visitor}; /// # @@ -78,11 +77,10 @@ /// called `V`. A different type parameter and a different lifetime can be /// specified explicitly if necessary. /// -/// ```edition2018 -/// # use std::marker::PhantomData; -/// # +/// ```edition2021 /// # use serde::forward_to_deserialize_any; /// # use serde::de::{value, Deserializer, Visitor}; +/// # use std::marker::PhantomData; /// # /// # struct MyDeserializer(PhantomData); /// # @@ -105,9 +103,9 @@ /// # } /// ``` /// -/// [`Deserializer`]: trait.Deserializer.html -/// [`Visitor`]: de/trait.Visitor.html -/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any +/// [`Deserializer`]: crate::Deserializer +/// [`Visitor`]: crate::de::Visitor +/// [`Deserializer::deserialize_any`]: crate::Deserializer::deserialize_any #[macro_export(local_inner_macros)] macro_rules! forward_to_deserialize_any { (<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => { @@ -124,7 +122,7 @@ macro_rules! forward_to_deserialize_any { macro_rules! forward_to_deserialize_any_method { ($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => { #[inline] - fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::export::Result<$v::Value, Self::Error> + fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::__private::Result<$v::Value, >::Error> where $v: $crate::de::Visitor<$l>, { @@ -155,9 +153,7 @@ macro_rules! forward_to_deserialize_any_helper { forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()} }; (i128<$l:tt, $v:ident>) => { - serde_if_integer128! { - forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()} - } + forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()} }; (u8<$l:tt, $v:ident>) => { forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()} @@ -172,9 +168,7 @@ macro_rules! forward_to_deserialize_any_helper { forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()} }; (u128<$l:tt, $v:ident>) => { - serde_if_integer128! { - forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()} - } + forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()} }; (f32<$l:tt, $v:ident>) => { forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()} diff --git a/serde_core/src/private/content.rs b/serde_core/src/private/content.rs new file mode 100644 index 000000000..f29a9b527 --- /dev/null +++ b/serde_core/src/private/content.rs @@ -0,0 +1,39 @@ +use crate::lib::*; + +// Used from generated code to buffer the contents of the Deserializer when +// deserializing untagged enums and internally tagged enums. +// +// Not public API. Use serde-value instead. +// +// Obsoleted by format-specific buffer types (https://github.com/serde-rs/serde/pull/2912). +#[doc(hidden)] +pub enum Content<'de> { + Bool(bool), + + U8(u8), + U16(u16), + U32(u32), + U64(u64), + + I8(i8), + I16(i16), + I32(i32), + I64(i64), + + F32(f32), + F64(f64), + + Char(char), + String(String), + Str(&'de str), + ByteBuf(Vec), + Bytes(&'de [u8]), + + None, + Some(Box>), + + Unit, + Newtype(Box>), + Seq(Vec>), + Map(Vec<(Content<'de>, Content<'de>)>), +} diff --git a/serde/src/private/macros.rs b/serde_core/src/private/doc.rs similarity index 82% rename from serde/src/private/macros.rs rename to serde_core/src/private/doc.rs index 4f7054f5d..2cc07f0d9 100644 --- a/serde/src/private/macros.rs +++ b/serde_core/src/private/doc.rs @@ -1,3 +1,38 @@ +// Used only by Serde doc tests. Not public API. + +use crate::lib::*; + +use crate::ser; + +#[doc(hidden)] +#[derive(Debug)] +pub struct Error; + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl ser::Error for Error { + fn custom(_: T) -> Self + where + T: Display, + { + unimplemented!() + } +} + +#[cfg(feature = "std")] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl error::Error for Error { + fn description(&self) -> &str { + unimplemented!() + } +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl Display for Error { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } +} + #[doc(hidden)] #[macro_export] macro_rules! __private_serialize { @@ -10,19 +45,6 @@ macro_rules! __private_serialize { }; } -#[doc(hidden)] -#[macro_export] -macro_rules! __private_deserialize { - () => { - trait Deserialize<'de>: Sized { - fn deserialize(deserializer: D) -> Result - where - D: $crate::Deserializer<'de>; - } - }; -} - -/// Used only by Serde doc tests. Not public API. #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! __serialize_unimplemented { @@ -37,7 +59,10 @@ macro_rules! __serialize_unimplemented { #[macro_export] macro_rules! __serialize_unimplemented_method { ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => { - fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::export::Result { + fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result + where + $($t: ?Sized + $crate::Serialize,)* + { unimplemented!() } }; diff --git a/serde_core/src/private/mod.rs b/serde_core/src/private/mod.rs new file mode 100644 index 000000000..dd5f93fe9 --- /dev/null +++ b/serde_core/src/private/mod.rs @@ -0,0 +1,21 @@ +#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))] +mod content; +mod seed; + +// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed. +#[doc(hidden)] +pub mod doc; + +#[doc(hidden)] +pub mod size_hint; + +#[doc(hidden)] +pub mod string; + +#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))] +#[doc(hidden)] +pub use self::content::Content; +#[doc(hidden)] +pub use self::seed::InPlaceSeed; +#[doc(hidden)] +pub use crate::lib::result::Result; diff --git a/serde_core/src/private/seed.rs b/serde_core/src/private/seed.rs new file mode 100644 index 000000000..bcf267cb0 --- /dev/null +++ b/serde_core/src/private/seed.rs @@ -0,0 +1,20 @@ +use crate::de::{Deserialize, DeserializeSeed, Deserializer}; + +/// A DeserializeSeed helper for implementing deserialize_in_place Visitors. +/// +/// Wraps a mutable reference and calls deserialize_in_place on it. +pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T); + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T> +where + T: Deserialize<'de>, +{ + type Value = (); + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize_in_place(deserializer, self.0) + } +} diff --git a/serde_core/src/private/size_hint.rs b/serde_core/src/private/size_hint.rs new file mode 100644 index 000000000..783281b46 --- /dev/null +++ b/serde_core/src/private/size_hint.rs @@ -0,0 +1,30 @@ +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::lib::*; + +pub fn from_bounds(iter: &I) -> Option +where + I: Iterator, +{ + helper(iter.size_hint()) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn cautious(hint: Option) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + if mem::size_of::() == 0 { + 0 + } else { + cmp::min( + hint.unwrap_or(0), + MAX_PREALLOC_BYTES / mem::size_of::(), + ) + } +} + +fn helper(bounds: (usize, Option)) -> Option { + match bounds { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } +} diff --git a/serde_core/src/private/string.rs b/serde_core/src/private/string.rs new file mode 100644 index 000000000..c8121a0da --- /dev/null +++ b/serde_core/src/private/string.rs @@ -0,0 +1,23 @@ +use crate::lib::*; + +#[cfg(any(feature = "std", feature = "alloc"))] +#[doc(hidden)] +pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> { + String::from_utf8_lossy(bytes) +} + +// The generated code calls this like: +// +// let value = &_serde::__private::from_utf8_lossy(bytes); +// Err(_serde::de::Error::unknown_variant(value, VARIANTS)) +// +// so it is okay for the return type to be different from the std case as long +// as the above works. +#[cfg(not(any(feature = "std", feature = "alloc")))] +#[doc(hidden)] +pub fn from_utf8_lossy(bytes: &[u8]) -> &str { + // Three unicode replacement characters if it fails. They look like a + // white-on-black question mark. The user will recognize it as invalid + // UTF-8. + str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}") +} diff --git a/serde/src/ser/fmt.rs b/serde_core/src/ser/fmt.rs similarity index 84% rename from serde/src/ser/fmt.rs rename to serde_core/src/ser/fmt.rs index e7e09a1bf..4b1549f08 100644 --- a/serde/src/ser/fmt.rs +++ b/serde_core/src/ser/fmt.rs @@ -1,5 +1,5 @@ -use lib::*; -use ser::{Error, Impossible, Serialize, Serializer}; +use crate::lib::*; +use crate::ser::{Error, Impossible, Serialize, Serializer}; impl Error for fmt::Error { fn custom(_msg: T) -> Self { @@ -17,8 +17,9 @@ macro_rules! fmt_primitives { }; } -/// ```edition2018 -/// use serde::Serialize; +/// ```edition2021 +/// use serde::ser::Serialize; +/// use serde_derive::Serialize; /// use std::fmt::{self, Display}; /// /// #[derive(Serialize)] @@ -34,7 +35,7 @@ macro_rules! fmt_primitives { /// } /// } /// ``` -impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { +impl<'a> Serializer for &mut fmt::Formatter<'a> { type Ok = (); type Error = fmt::Error; type SerializeSeq = Impossible<(), fmt::Error>; @@ -51,10 +52,12 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { serialize_i16: i16, serialize_i32: i32, serialize_i64: i64, + serialize_i128: i128, serialize_u8: u8, serialize_u16: u16, serialize_u32: u32, serialize_u64: u64, + serialize_u128: u128, serialize_f32: f32, serialize_f64: f64, serialize_char: char, @@ -62,13 +65,6 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { serialize_unit_struct: &'static str, } - serde_if_integer128! { - fmt_primitives! { - serialize_i128: i128, - serialize_u128: u128, - } - } - fn serialize_unit_variant( self, _name: &'static str, @@ -78,9 +74,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Display::fmt(variant, self) } - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Serialize::serialize(value, self) } @@ -93,9 +89,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn serialize_some(self, _value: &T) -> fmt::Result + fn serialize_some(self, _value: &T) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Err(fmt::Error) } @@ -104,7 +100,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, @@ -112,7 +108,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { _value: &T, ) -> fmt::Result where - T: Serialize, + T: ?Sized + Serialize, { Err(fmt::Error) } @@ -165,9 +161,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> { Err(fmt::Error) } - fn collect_str(self, value: &T) -> fmt::Result + fn collect_str(self, value: &T) -> fmt::Result where - T: Display, + T: ?Sized + Display, { Display::fmt(value, self) } diff --git a/serde/src/ser/impls.rs b/serde_core/src/ser/impls.rs similarity index 65% rename from serde/src/ser/impls.rs rename to serde_core/src/ser/impls.rs index 431a478cc..a7a175db9 100644 --- a/serde/src/ser/impls.rs +++ b/serde_core/src/ser/impls.rs @@ -1,6 +1,6 @@ -use lib::*; +use crate::lib::*; -use ser::{Error, Serialize, SerializeTuple, Serializer}; +use crate::ser::{Error, Serialize, SerializeTuple, Serializer}; //////////////////////////////////////////////////////////////////////////////// @@ -24,20 +24,17 @@ primitive_impl!(i8, serialize_i8); primitive_impl!(i16, serialize_i16); primitive_impl!(i32, serialize_i32); primitive_impl!(i64, serialize_i64); +primitive_impl!(i128, serialize_i128); primitive_impl!(usize, serialize_u64 as u64); primitive_impl!(u8, serialize_u8); primitive_impl!(u16, serialize_u16); primitive_impl!(u32, serialize_u32); primitive_impl!(u64, serialize_u64); +primitive_impl!(u128, serialize_u128); primitive_impl!(f32, serialize_f32); primitive_impl!(f64, serialize_f64); primitive_impl!(char, serialize_char); -serde_if_integer128! { - primitive_impl!(i128, serialize_i128); - primitive_impl!(u128, serialize_u128); -} - //////////////////////////////////////////////////////////////////////////////// impl Serialize for str { @@ -51,6 +48,7 @@ impl Serialize for str { } #[cfg(any(feature = "std", feature = "alloc"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl Serialize for String { #[inline] fn serialize(&self, serializer: S) -> Result @@ -72,7 +70,8 @@ impl<'a> Serialize for fmt::Arguments<'a> { //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_cstr)))] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for CStr { #[inline] fn serialize(&self, serializer: S) -> Result @@ -83,7 +82,8 @@ impl Serialize for CStr { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl Serialize for CString { #[inline] fn serialize(&self, serializer: S) -> Result @@ -114,7 +114,10 @@ where //////////////////////////////////////////////////////////////////////////////// -impl Serialize for PhantomData { +impl Serialize for PhantomData +where + T: ?Sized, +{ #[inline] fn serialize(&self, serializer: S) -> Result where @@ -133,7 +136,7 @@ impl Serialize for [T; 0] { where S: Serializer, { - try!(serializer.serialize_tuple(0)).end() + tri!(serializer.serialize_tuple(0)).end() } } @@ -149,9 +152,9 @@ macro_rules! array_impls { where S: Serializer, { - let mut seq = try!(serializer.serialize_tuple($len)); + let mut seq = tri!(serializer.serialize_tuple($len)); for e in self { - try!(seq.serialize_element(e)); + tri!(seq.serialize_element(e)); } seq.end() } @@ -182,13 +185,15 @@ where } } -#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! seq_impl { - ($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)* >) => { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* impl Serialize for $ty where - T: Serialize $(+ $tbound1 $(+ $tbound2)*)*, - $($typaram: $bound,)* + T: Serialize, { #[inline] fn serialize(&self, serializer: S) -> Result @@ -201,23 +206,41 @@ macro_rules! seq_impl { } } -#[cfg(any(feature = "std", feature = "alloc"))] -seq_impl!(BinaryHeap); +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BinaryHeap +} -#[cfg(any(feature = "std", feature = "alloc"))] -seq_impl!(BTreeSet); +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeSet +} -#[cfg(feature = "std")] -seq_impl!(HashSet); +seq_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashSet +} -#[cfg(any(feature = "std", feature = "alloc"))] -seq_impl!(LinkedList); +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + LinkedList +} -#[cfg(any(feature = "std", feature = "alloc"))] -seq_impl!(Vec); +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + Vec +} -#[cfg(any(feature = "std", feature = "alloc"))] -seq_impl!(VecDeque); +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + VecDeque +} //////////////////////////////////////////////////////////////////////////////// @@ -230,16 +253,32 @@ where S: Serializer, { use super::SerializeStruct; - let mut state = try!(serializer.serialize_struct("Range", 2)); - try!(state.serialize_field("start", &self.start)); - try!(state.serialize_field("end", &self.end)); + let mut state = tri!(serializer.serialize_struct("Range", 2)); + tri!(state.serialize_field("start", &self.start)); + tri!(state.serialize_field("end", &self.end)); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for RangeFrom +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + let mut state = tri!(serializer.serialize_struct("RangeFrom", 1)); + tri!(state.serialize_field("start", &self.start)); state.end() } } //////////////////////////////////////////////////////////////////////////////// -#[cfg(range_inclusive)] impl Serialize for RangeInclusive where Idx: Serialize, @@ -249,16 +288,32 @@ where S: Serializer, { use super::SerializeStruct; - let mut state = try!(serializer.serialize_struct("RangeInclusive", 2)); - try!(state.serialize_field("start", &self.start())); - try!(state.serialize_field("end", &self.end())); + let mut state = tri!(serializer.serialize_struct("RangeInclusive", 2)); + tri!(state.serialize_field("start", &self.start())); + tri!(state.serialize_field("end", &self.end())); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for RangeTo +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + let mut state = tri!(serializer.serialize_struct("RangeTo", 1)); + tri!(state.serialize_field("end", &self.end)); state.end() } } //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(ops_bound, collections_bound))] impl Serialize for Bound where T: Serialize, @@ -292,6 +347,7 @@ impl Serialize for () { } #[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl Serialize for ! { fn serialize(&self, _serializer: S) -> Result where @@ -306,28 +362,46 @@ impl Serialize for ! { macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( + #[cfg_attr(docsrs, doc(hidden))] impl<$($name),+> Serialize for ($($name,)+) where $($name: Serialize,)+ { - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tuple = try!(serializer.serialize_tuple($len)); - $( - try!(tuple.serialize_element(&self.$n)); - )+ - tuple.end() - } + tuple_impl_body!($len => ($($n)+)); } )+ - } + }; +} + +macro_rules! tuple_impl_body { + ($len:expr => ($($n:tt)+)) => { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tuple = tri!(serializer.serialize_tuple($len)); + $( + tri!(tuple.serialize_element(&self.$n)); + )+ + tuple.end() + } + }; +} + +#[cfg_attr(docsrs, doc(fake_variadic))] +#[cfg_attr( + docsrs, + doc = "This trait is implemented for tuples up to 16 items long." +)] +impl Serialize for (T,) +where + T: Serialize, +{ + tuple_impl_body!(1 => (0)); } tuple_impls! { - 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) @@ -347,14 +421,16 @@ tuple_impls! { //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(feature = "std", feature = "alloc"))] macro_rules! map_impl { - ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* impl Serialize for $ty where - K: Serialize $(+ $kbound1 $(+ $kbound2)*)*, + K: Serialize, V: Serialize, - $($typaram: $bound,)* { #[inline] fn serialize(&self, serializer: S) -> Result @@ -367,20 +443,26 @@ macro_rules! map_impl { } } -#[cfg(any(feature = "std", feature = "alloc"))] -map_impl!(BTreeMap); +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeMap +} -#[cfg(feature = "std")] -map_impl!(HashMap); +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashMap +} //////////////////////////////////////////////////////////////////////////////// macro_rules! deref_impl { ( - $(#[doc = $doc:tt])* + $(#[$attr:meta])* <$($desc:tt)+ ) => { - $(#[doc = $doc])* + $(#[$attr])* impl <$($desc)+ { #[inline] fn serialize(&self, serializer: S) -> Result @@ -393,13 +475,20 @@ macro_rules! deref_impl { }; } -deref_impl!(<'a, T: ?Sized> Serialize for &'a T where T: Serialize); -deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize); +deref_impl! { + <'a, T> Serialize for &'a T where T: ?Sized + Serialize +} -#[cfg(any(feature = "std", feature = "alloc"))] -deref_impl!( Serialize for Box where T: Serialize); +deref_impl! { + <'a, T> Serialize for &'a mut T where T: ?Sized + Serialize +} + +deref_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + Serialize for Box where T: ?Sized + Serialize +} -#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] deref_impl! { /// This impl requires the [`"rc"`] Cargo feature of Serde. /// @@ -409,10 +498,11 @@ deref_impl! { /// repeated data. /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc - Serialize for Rc where T: Serialize + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Serialize for Rc where T: ?Sized + Serialize } -#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] deref_impl! { /// This impl requires the [`"rc"`] Cargo feature of Serde. /// @@ -422,11 +512,16 @@ deref_impl! { /// repeated data. /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc - Serialize for Arc where T: Serialize + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Serialize for Arc where T: ?Sized + Serialize } -#[cfg(any(feature = "std", feature = "alloc"))] -deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned); +deref_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + <'a, T> Serialize for Cow<'a, T> where T: ?Sized + Serialize + ToOwned +} //////////////////////////////////////////////////////////////////////////////// @@ -434,9 +529,13 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl Serialize for RcWeak +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) +)] +impl Serialize for RcWeak where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -450,9 +549,13 @@ where /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl Serialize for ArcWeak +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))) +)] +impl Serialize for ArcWeak where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -465,9 +568,8 @@ where //////////////////////////////////////////////////////////////////////////////// macro_rules! nonzero_integers { - ( $( $T: ident, )+ ) => { + ($($T:ident,)+) => { $( - #[cfg(num_nonzero)] impl Serialize for num::$T { fn serialize(&self, serializer: S) -> Result where @@ -480,34 +582,19 @@ macro_rules! nonzero_integers { } } -nonzero_integers! { - NonZeroU8, - NonZeroU16, - NonZeroU32, - NonZeroU64, - NonZeroUsize, -} - -#[cfg(num_nonzero_signed)] nonzero_integers! { NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, + NonZeroI128, NonZeroIsize, -} - -// Currently 128-bit integers do not work on Emscripten targets so we need an -// additional `#[cfg]` -serde_if_integer128! { - nonzero_integers! { - NonZeroU128, - } - - #[cfg(num_nonzero_signed)] - nonzero_integers! { - NonZeroI128, - } + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize, } impl Serialize for Cell @@ -524,7 +611,7 @@ where impl Serialize for RefCell where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -538,9 +625,10 @@ where } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for Mutex where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -554,9 +642,10 @@ where } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for RwLock where - T: Serialize, + T: ?Sized + Serialize, { fn serialize(&self, serializer: S) -> Result where @@ -571,6 +660,8 @@ where //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] impl Serialize for Result where T: Serialize, @@ -591,16 +682,15 @@ where //////////////////////////////////////////////////////////////////////////////// -#[cfg(any(core_duration, feature = "std"))] impl Serialize for Duration { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use super::SerializeStruct; - let mut state = try!(serializer.serialize_struct("Duration", 2)); - try!(state.serialize_field("secs", &self.as_secs())); - try!(state.serialize_field("nanos", &self.subsec_nanos())); + let mut state = tri!(serializer.serialize_struct("Duration", 2)); + tri!(state.serialize_field("secs", &self.as_secs())); + tri!(state.serialize_field("nanos", &self.subsec_nanos())); state.end() } } @@ -608,18 +698,20 @@ impl Serialize for Duration { //////////////////////////////////////////////////////////////////////////////// #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for SystemTime { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use super::SerializeStruct; - let duration_since_epoch = self - .duration_since(UNIX_EPOCH) - .map_err(|_| S::Error::custom("SystemTime must be later than UNIX_EPOCH"))?; - let mut state = try!(serializer.serialize_struct("SystemTime", 2)); - try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs())); - try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos())); + let duration_since_epoch = match self.duration_since(UNIX_EPOCH) { + Ok(duration_since_epoch) => duration_since_epoch, + Err(_) => return Err(S::Error::custom("SystemTime must be later than UNIX_EPOCH")), + }; + let mut state = tri!(serializer.serialize_struct("SystemTime", 2)); + tri!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs())); + tri!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos())); state.end() } } @@ -630,27 +722,17 @@ impl Serialize for SystemTime { /// statically known to never have more than a constant `MAX_LEN` bytes. /// /// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes. -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] macro_rules! serialize_display_bounded_length { ($value:expr, $max:expr, $serializer:expr) => {{ let mut buffer = [0u8; $max]; - let remaining_len = { - let mut remaining = &mut buffer[..]; - write!(remaining, "{}", $value).unwrap(); - remaining.len() - }; - let written_len = buffer.len() - remaining_len; - let written = &buffer[..written_len]; - - // write! only provides fmt::Formatter to Display implementations, which - // has methods write_str and write_char but no method to write arbitrary - // bytes. Therefore `written` must be valid UTF-8. - let written_str = str::from_utf8(written).expect("must be valid UTF-8"); - $serializer.serialize_str(written_str) + let mut writer = crate::format::Buf::new(&mut buffer); + write!(&mut writer, "{}", $value).unwrap(); + $serializer.serialize_str(writer.as_str()) }}; } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::IpAddr { fn serialize(&self, serializer: S) -> Result where @@ -674,7 +756,53 @@ impl Serialize for net::IpAddr { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] +const DEC_DIGITS_LUT: &[u8] = b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +#[cfg(any(feature = "std", not(no_core_net)))] +#[inline] +fn format_u8(mut n: u8, out: &mut [u8]) -> usize { + if n >= 100 { + let d1 = ((n % 100) << 1) as usize; + n /= 100; + out[0] = b'0' + n; + out[1] = DEC_DIGITS_LUT[d1]; + out[2] = DEC_DIGITS_LUT[d1 + 1]; + 3 + } else if n >= 10 { + let d1 = (n << 1) as usize; + out[0] = DEC_DIGITS_LUT[d1]; + out[1] = DEC_DIGITS_LUT[d1 + 1]; + 2 + } else { + out[0] = b'0' + n; + 1 + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +#[test] +fn test_format_u8() { + let mut i = 0u8; + + loop { + let mut buf = [0u8; 3]; + let written = format_u8(i, &mut buf); + assert_eq!(i.to_string().as_bytes(), &buf[..written]); + + match i.checked_add(1) { + Some(next) => i = next, + None => break, + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::Ipv4Addr { fn serialize(&self, serializer: S) -> Result where @@ -683,14 +811,22 @@ impl Serialize for net::Ipv4Addr { if serializer.is_human_readable() { const MAX_LEN: usize = 15; debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); - serialize_display_bounded_length!(self, MAX_LEN, serializer) + let mut buf = [b'.'; MAX_LEN]; + let mut written = format_u8(self.octets()[0], &mut buf); + for oct in &self.octets()[1..] { + // Skip over delimiters that we initialized buf with + written += format_u8(*oct, &mut buf[written + 1..]) + 1; + } + // Safety: We've only written ASCII bytes to the buffer, so it is valid UTF-8 + let buf = unsafe { str::from_utf8_unchecked(&buf[..written]) }; + serializer.serialize_str(buf) } else { self.octets().serialize(serializer) } } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::Ipv6Addr { fn serialize(&self, serializer: S) -> Result where @@ -706,7 +842,7 @@ impl Serialize for net::Ipv6Addr { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::SocketAddr { fn serialize(&self, serializer: S) -> Result where @@ -730,7 +866,7 @@ impl Serialize for net::SocketAddr { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::SocketAddrV4 { fn serialize(&self, serializer: S) -> Result where @@ -746,7 +882,7 @@ impl Serialize for net::SocketAddrV4 { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(no_core_net)))] impl Serialize for net::SocketAddrV6 { fn serialize(&self, serializer: S) -> Result where @@ -768,6 +904,7 @@ impl Serialize for net::SocketAddrV6 { //////////////////////////////////////////////////////////////////////////////// #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for Path { fn serialize(&self, serializer: S) -> Result where @@ -781,6 +918,7 @@ impl Serialize for Path { } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Serialize for PathBuf { fn serialize(&self, serializer: S) -> Result where @@ -791,6 +929,7 @@ impl Serialize for PathBuf { } #[cfg(all(feature = "std", any(unix, windows)))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))] impl Serialize for OsStr { #[cfg(unix)] fn serialize(&self, serializer: S) -> Result @@ -813,6 +952,7 @@ impl Serialize for OsStr { } #[cfg(all(feature = "std", any(unix, windows)))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))] impl Serialize for OsString { fn serialize(&self, serializer: S) -> Result where @@ -837,7 +977,20 @@ where } } -#[cfg(core_reverse)] +#[cfg(not(no_core_num_saturating))] +impl Serialize for Saturating +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + impl Serialize for Reverse where T: Serialize, @@ -853,30 +1006,40 @@ where //////////////////////////////////////////////////////////////////////////////// -#[cfg(all(feature = "std", std_atomic))] +#[cfg(all(feature = "std", not(no_std_atomic)))] macro_rules! atomic_impl { - ($($ty:ident)*) => { + ($($ty:ident $size:expr)*) => { $( + #[cfg(any(no_target_has_atomic, target_has_atomic = $size))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))] impl Serialize for $ty { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - self.load(Ordering::SeqCst).serialize(serializer) + // Matches the atomic ordering used in libcore for the Debug impl + self.load(Ordering::Relaxed).serialize(serializer) } } )* } } -#[cfg(all(feature = "std", std_atomic))] +#[cfg(all(feature = "std", not(no_std_atomic)))] atomic_impl! { - AtomicBool - AtomicI8 AtomicI16 AtomicI32 AtomicIsize - AtomicU8 AtomicU16 AtomicU32 AtomicUsize + AtomicBool "8" + AtomicI8 "8" + AtomicI16 "16" + AtomicI32 "32" + AtomicIsize "ptr" + AtomicU8 "8" + AtomicU16 "16" + AtomicU32 "32" + AtomicUsize "ptr" } -#[cfg(all(feature = "std", std_atomic64))] +#[cfg(all(feature = "std", not(no_std_atomic64)))] atomic_impl! { - AtomicI64 AtomicU64 + AtomicI64 "64" + AtomicU64 "64" } diff --git a/serde/src/ser/impossible.rs b/serde_core/src/ser/impossible.rs similarity index 73% rename from serde/src/ser/impossible.rs rename to serde_core/src/ser/impossible.rs index 90bab29a0..fe69ae24e 100644 --- a/serde/src/ser/impossible.rs +++ b/serde_core/src/ser/impossible.rs @@ -1,8 +1,8 @@ //! This module contains `Impossible` serializer and its implementations. -use lib::*; +use crate::lib::*; -use ser::{ +use crate::ser::{ self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, }; @@ -15,9 +15,9 @@ use ser::{ /// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`], /// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`]. /// -/// ```edition2018 +/// ```edition2021 /// # use serde::ser::{Serializer, Impossible}; -/// # use serde::private::ser::Error; +/// # use serde_core::__private::doc::Error; /// # /// # struct MySerializer; /// # @@ -41,7 +41,7 @@ use ser::{ /// } /// /// /* other Serializer methods */ -/// # serde::__serialize_unimplemented! { +/// # serde_core::__serialize_unimplemented! { /// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes none some /// # unit unit_struct unit_variant newtype_struct newtype_variant /// # tuple tuple_struct tuple_variant map struct struct_variant @@ -49,14 +49,14 @@ use ser::{ /// } /// ``` /// -/// [`Serializer`]: trait.Serializer.html -/// [`SerializeSeq`]: trait.SerializeSeq.html -/// [`SerializeTuple`]: trait.SerializeTuple.html -/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html -/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html -/// [`SerializeMap`]: trait.SerializeMap.html -/// [`SerializeStruct`]: trait.SerializeStruct.html -/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html +/// [`Serializer`]: crate::Serializer +/// [`SerializeSeq`]: crate::ser::SerializeSeq +/// [`SerializeTuple`]: crate::ser::SerializeTuple +/// [`SerializeTupleStruct`]: crate::ser::SerializeTupleStruct +/// [`SerializeTupleVariant`]: crate::ser::SerializeTupleVariant +/// [`SerializeMap`]: crate::ser::SerializeMap +/// [`SerializeStruct`]: crate::ser::SerializeStruct +/// [`SerializeStructVariant`]: crate::ser::SerializeStructVariant pub struct Impossible { void: Void, ok: PhantomData, @@ -72,9 +72,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_element(&mut self, value: &T) -> Result<(), Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -92,9 +92,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_element(&mut self, value: &T) -> Result<(), Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -112,9 +112,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -132,9 +132,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -152,17 +152,17 @@ where type Ok = Ok; type Error = Error; - fn serialize_key(&mut self, key: &T) -> Result<(), Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; match self.void {} } - fn serialize_value(&mut self, value: &T) -> Result<(), Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = value; match self.void {} @@ -180,9 +180,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; let _ = value; @@ -201,9 +201,9 @@ where type Ok = Ok; type Error = Error; - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> where - T: Serialize, + T: ?Sized + Serialize, { let _ = key; let _ = value; diff --git a/serde/src/ser/mod.rs b/serde_core/src/ser/mod.rs similarity index 85% rename from serde/src/ser/mod.rs rename to serde_core/src/ser/mod.rs index 8a4b2e366..62e59d981 100644 --- a/serde/src/ser/mod.rs +++ b/serde_core/src/ser/mod.rs @@ -30,7 +30,7 @@ //! # The Serializer trait //! //! [`Serializer`] implementations are provided by third-party crates, for -//! example [`serde_json`], [`serde_yaml`] and [`bincode`]. +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. //! //! A partial list of well-maintained formats is given on the [Serde //! website][data formats]. @@ -61,8 +61,8 @@ //! - RefCell\ //! - Mutex\ //! - RwLock\ -//! - Rc\ *(if* features = ["rc"] *is enabled)* -//! - Arc\ *(if* features = ["rc"] *is enabled)* +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* //! - **Collection types**: //! - BTreeMap\ //! - BTreeSet\ @@ -97,9 +97,9 @@ //! //! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html -//! [`Serialize`]: ../trait.Serialize.html -//! [`Serializer`]: ../trait.Serializer.html -//! [`bincode`]: https://github.com/servo/bincode +//! [`Serialize`]: crate::Serialize +//! [`Serializer`]: crate::Serializer +//! [`postcard`]: https://github.com/jamesmunns/postcard //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json @@ -107,7 +107,7 @@ //! [derive section of the manual]: https://serde.rs/derive.html //! [data formats]: https://serde.rs/#data-formats -use lib::*; +use crate::lib::*; mod fmt; mod impls; @@ -115,12 +115,15 @@ mod impossible; pub use self::impossible::Impossible; +#[cfg(all(not(feature = "std"), no_core_error))] +#[doc(no_inline)] +pub use crate::std_error::Error as StdError; +#[cfg(not(any(feature = "std", no_core_error)))] +#[doc(no_inline)] +pub use core::error::Error as StdError; #[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; //////////////////////////////////////////////////////////////////////////////// @@ -136,6 +139,12 @@ macro_rules! declare_error_trait { /// type appropriate for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html + #[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::Error` is not satisfied", + ) + )] pub trait Error: Sized $(+ $($supertrait)::+)* { /// Used when a [`Serialize`] implementation encounters any error /// while serializing a type. @@ -146,7 +155,7 @@ macro_rules! declare_error_trait { /// For example, a filesystem [`Path`] may refuse to serialize /// itself if it contains invalid UTF-8 data. /// - /// ```edition2018 + /// ```edition2021 /// # struct Path; /// # /// # impl Path { @@ -170,8 +179,8 @@ macro_rules! declare_error_trait { /// } /// ``` /// - /// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html - /// [`Serialize`]: ../trait.Serialize.html + /// [`Path`]: std::path::Path + /// [`Serialize`]: crate::Serialize fn custom(msg: T) -> Self where T: Display; @@ -191,8 +200,8 @@ declare_error_trait!(Error: Sized + Debug + Display); /// by Serde. /// /// Serde provides `Serialize` implementations for many Rust primitive and -/// standard library types. The complete list is [here][ser]. All of these can -/// be serialized using Serde out of the box. +/// standard library types. The complete list is [here][crate::ser]. All of +/// these can be serialized using Serde out of the box. /// /// Additionally, Serde provides a procedural macro called [`serde_derive`] to /// automatically generate `Serialize` implementations for structs and enums in @@ -212,14 +221,23 @@ declare_error_trait!(Error: Sized + Debug + Display); /// [`linked-hash-map`]: https://crates.io/crates/linked-hash-map /// [`serde_derive`]: https://crates.io/crates/serde_derive /// [derive section of the manual]: https://serde.rs/derive.html -/// [ser]: https://docs.serde.rs/serde/ser/index.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + // Prevents `serde_core::ser::Serialize` appearing in the error message + // in projects with no direct dependency on serde_core. + message = "the trait bound `{Self}: serde::Serialize` is not satisfied", + note = "for local types consider adding `#[derive(serde::Serialize)]` to your `{Self}` type", + note = "for types from other crates check whether the crate offers a `serde` feature flag", + ) +)] pub trait Serialize { /// Serialize this value into the given Serde serializer. /// /// See the [Implementing `Serialize`] section of the manual for more /// information about how to implement this method. /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// /// struct Person { @@ -314,7 +332,7 @@ pub trait Serialize { /// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`. /// /// Many Serde serializers produce text or binary data as output, for example -/// JSON or Bincode. This is not a requirement of the `Serializer` trait, and +/// JSON or Postcard. This is not a requirement of the `Serializer` trait, and /// there are serializers that do not produce text or binary output. One example /// is the `serde_json::value::Serializer` (distinct from the main `serde_json` /// serializer) that produces a `serde_json::Value` data structure in memory as @@ -328,6 +346,12 @@ pub trait Serialize { /// a basic JSON `Serializer`. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::Serializer` is not satisfied", + ) +)] pub trait Serializer: Sized { /// The output type produced by this `Serializer` during successful /// serialization. Most serializers that produce text or binary output @@ -336,7 +360,7 @@ pub trait Serializer: Sized { /// in-memory data structures may be simplified by using `Ok` to propagate /// the data structure around. /// - /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`io::Write`]: std::io::Write type Ok; /// The error type when some error occurs during serialization. @@ -386,10 +410,10 @@ pub trait Serializer: Sized { /// Serialize a `bool` value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for bool { /// fn serialize(&self, serializer: S) -> Result @@ -408,10 +432,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `i64` and /// forward to `serialize_i64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for i8 { /// fn serialize(&self, serializer: S) -> Result @@ -430,10 +454,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `i64` and /// forward to `serialize_i64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for i16 { /// fn serialize(&self, serializer: S) -> Result @@ -452,10 +476,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `i64` and /// forward to `serialize_i64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for i32 { /// fn serialize(&self, serializer: S) -> Result @@ -470,10 +494,10 @@ pub trait Serializer: Sized { /// Serialize an `i64` value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for i64 { /// fn serialize(&self, serializer: S) -> Result @@ -486,30 +510,27 @@ pub trait Serializer: Sized { /// ``` fn serialize_i64(self, v: i64) -> Result; - serde_if_integer128! { - /// Serialize an `i128` value. - /// - /// ```edition2018 - /// # use serde::Serializer; - /// # - /// # serde::__private_serialize!(); - /// # - /// impl Serialize for i128 { - /// fn serialize(&self, serializer: S) -> Result - /// where - /// S: Serializer, - /// { - /// serializer.serialize_i128(*self) - /// } - /// } - /// ``` - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default behavior unconditionally returns an error. - fn serialize_i128(self, v: i128) -> Result { - let _ = v; - Err(Error::custom("i128 is not supported")) - } + /// Serialize an `i128` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i128 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i128(*self) + /// } + /// } + /// ``` + /// + /// The default behavior unconditionally returns an error. + fn serialize_i128(self, v: i128) -> Result { + let _ = v; + Err(Error::custom("i128 is not supported")) } /// Serialize a `u8` value. @@ -518,10 +539,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `u64` and /// forward to `serialize_u64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for u8 { /// fn serialize(&self, serializer: S) -> Result @@ -540,10 +561,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `u64` and /// forward to `serialize_u64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for u16 { /// fn serialize(&self, serializer: S) -> Result @@ -562,10 +583,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `u64` and /// forward to `serialize_u64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for u32 { /// fn serialize(&self, serializer: S) -> Result @@ -580,10 +601,10 @@ pub trait Serializer: Sized { /// Serialize a `u64` value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for u64 { /// fn serialize(&self, serializer: S) -> Result @@ -596,30 +617,27 @@ pub trait Serializer: Sized { /// ``` fn serialize_u64(self, v: u64) -> Result; - serde_if_integer128! { - /// Serialize a `u128` value. - /// - /// ```edition2018 - /// # use serde::Serializer; - /// # - /// # serde::__private_serialize!(); - /// # - /// impl Serialize for u128 { - /// fn serialize(&self, serializer: S) -> Result - /// where - /// S: Serializer, - /// { - /// serializer.serialize_u128(*self) - /// } - /// } - /// ``` - /// - /// This method is available only on Rust compiler versions >=1.26. The - /// default behavior unconditionally returns an error. - fn serialize_u128(self, v: u128) -> Result { - let _ = v; - Err(Error::custom("u128 is not supported")) - } + /// Serialize a `u128` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u128 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u128(*self) + /// } + /// } + /// ``` + /// + /// The default behavior unconditionally returns an error. + fn serialize_u128(self, v: u128) -> Result { + let _ = v; + Err(Error::custom("u128 is not supported")) } /// Serialize an `f32` value. @@ -628,10 +646,10 @@ pub trait Serializer: Sized { /// reasonable implementation would be to cast the value to `f64` and /// forward to `serialize_f64`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for f32 { /// fn serialize(&self, serializer: S) -> Result @@ -646,10 +664,10 @@ pub trait Serializer: Sized { /// Serialize an `f64` value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for f64 { /// fn serialize(&self, serializer: S) -> Result @@ -667,10 +685,10 @@ pub trait Serializer: Sized { /// If the format does not support characters, it is reasonable to serialize /// it as a single element `str` or a `u32`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for char { /// fn serialize(&self, serializer: S) -> Result @@ -685,10 +703,10 @@ pub trait Serializer: Sized { /// Serialize a `&str`. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for str { /// fn serialize(&self, serializer: S) -> Result @@ -709,9 +727,9 @@ pub trait Serializer: Sized { /// `serialize_seq`. If forwarded, the implementation looks usually just /// like this: /// - /// ```edition2018 + /// ```edition2021 /// # use serde::ser::{Serializer, SerializeSeq}; - /// # use serde::private::ser::Error; + /// # use serde_core::__private::doc::Error; /// # /// # struct MySerializer; /// # @@ -727,7 +745,7 @@ pub trait Serializer: Sized { /// seq.end() /// } /// # - /// # serde::__serialize_unimplemented! { + /// # serde_core::__serialize_unimplemented! { /// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str none some /// # unit unit_struct unit_variant newtype_struct newtype_variant /// # seq tuple tuple_struct tuple_variant map struct struct_variant @@ -738,7 +756,7 @@ pub trait Serializer: Sized { /// Serialize a [`None`] value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::{Serialize, Serializer}; /// # /// # enum Option { @@ -766,12 +784,12 @@ pub trait Serializer: Sized { /// # fn main() {} /// ``` /// - /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// [`None`]: core::option::Option::None fn serialize_none(self) -> Result; /// Serialize a [`Some(T)`] value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::{Serialize, Serializer}; /// # /// # enum Option { @@ -799,17 +817,17 @@ pub trait Serializer: Sized { /// # fn main() {} /// ``` /// - /// [`Some(T)`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some - fn serialize_some(self, value: &T) -> Result + /// [`Some(T)`]: core::option::Option::Some + fn serialize_some(self, value: &T) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a `()` value. /// - /// ```edition2018 + /// ```edition2021 /// # use serde::Serializer; /// # - /// # serde::__private_serialize!(); + /// # serde_core::__private_serialize!(); /// # /// impl Serialize for () { /// fn serialize(&self, serializer: S) -> Result @@ -826,7 +844,7 @@ pub trait Serializer: Sized { /// /// A reasonable implementation would be to forward to `serialize_unit`. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// /// struct Nothing; @@ -848,7 +866,7 @@ pub trait Serializer: Sized { /// this variant within the enum, and the `variant` is the name of the /// variant. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// /// enum E { @@ -881,7 +899,7 @@ pub trait Serializer: Sized { /// wrappers around the data they contain. A reasonable implementation would /// be to forward to `value.serialize(self)`. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// /// struct Millimeters(u8); @@ -895,13 +913,13 @@ pub trait Serializer: Sized { /// } /// } /// ``` - fn serialize_newtype_struct( + fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`. /// @@ -909,7 +927,7 @@ pub trait Serializer: Sized { /// this variant within the enum, and the `variant` is the name of the /// variant. The `value` is the data contained within this newtype variant. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// /// enum E { @@ -929,7 +947,7 @@ pub trait Serializer: Sized { /// } /// } /// ``` - fn serialize_newtype_variant( + fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, @@ -937,7 +955,7 @@ pub trait Serializer: Sized { value: &T, ) -> Result where - T: Serialize; + T: ?Sized + Serialize; /// Begin to serialize a variably sized sequence. This call must be /// followed by zero or more calls to `serialize_element`, then a call to @@ -947,7 +965,7 @@ pub trait Serializer: Sized { /// not be computable before the sequence is iterated. Some serializers only /// support sequences whose length is known up front. /// - /// ```edition2018 + /// ```edition2021 /// # use std::marker::PhantomData; /// # /// # struct Vec(PhantomData); @@ -960,14 +978,14 @@ pub trait Serializer: Sized { /// # /// # impl<'a, T> IntoIterator for &'a Vec { /// # type Item = &'a T; - /// # type IntoIter = Box>; + /// # type IntoIter = Box>; /// # /// # fn into_iter(self) -> Self::IntoIter { /// # unimplemented!() /// # } /// # } /// # - /// use serde::ser::{Serialize, Serializer, SerializeSeq}; + /// use serde::ser::{Serialize, SerializeSeq, Serializer}; /// /// impl Serialize for Vec /// where @@ -992,8 +1010,8 @@ pub trait Serializer: Sized { /// This call must be followed by zero or more calls to `serialize_element`, /// then a call to `end`. /// - /// ```edition2018 - /// use serde::ser::{Serialize, Serializer, SerializeTuple}; + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; /// /// # mod fool { /// # trait Serialize {} @@ -1022,7 +1040,7 @@ pub trait Serializer: Sized { /// } /// ``` /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeTuple, Serializer}; /// /// const VRAM_SIZE: usize = 386; @@ -1050,7 +1068,7 @@ pub trait Serializer: Sized { /// The `name` is the name of the tuple struct and the `len` is the number /// of data fields that will be serialized. /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; /// /// struct Rgb(u8, u8, u8); @@ -1082,7 +1100,7 @@ pub trait Serializer: Sized { /// this variant within the enum, the `variant` is the name of the variant, /// and the `len` is the number of data fields that will be serialized. /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; /// /// enum E { @@ -1128,7 +1146,7 @@ pub trait Serializer: Sized { /// be computable before the map is iterated. Some serializers only support /// maps whose length is known up front. /// - /// ```edition2018 + /// ```edition2021 /// # use std::marker::PhantomData; /// # /// # struct HashMap(PhantomData, PhantomData); @@ -1141,14 +1159,14 @@ pub trait Serializer: Sized { /// # /// # impl<'a, K, V> IntoIterator for &'a HashMap { /// # type Item = (&'a K, &'a V); - /// # type IntoIter = Box>; + /// # type IntoIter = Box>; /// # /// # fn into_iter(self) -> Self::IntoIter { /// # unimplemented!() /// # } /// # } /// # - /// use serde::ser::{Serialize, Serializer, SerializeMap}; + /// use serde::ser::{Serialize, SerializeMap, Serializer}; /// /// impl Serialize for HashMap /// where @@ -1174,9 +1192,10 @@ pub trait Serializer: Sized { /// then a call to `end`. /// /// The `name` is the name of the struct and the `len` is the number of - /// data fields that will be serialized. + /// data fields that will be serialized. `len` does not include fields + /// which are skipped with [`SerializeStruct::skip_field`]. /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// /// struct Rgb { @@ -1211,8 +1230,10 @@ pub trait Serializer: Sized { /// The `name` is the name of the enum, the `variant_index` is the index of /// this variant within the enum, the `variant` is the name of the variant, /// and the `len` is the number of data fields that will be serialized. + /// `len` does not include fields which are skipped with + /// [`SerializeStructVariant::skip_field`]. /// - /// ```edition2018 + /// ```edition2021 /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; /// /// enum E { @@ -1254,7 +1275,7 @@ pub trait Serializer: Sized { /// using [`serialize_seq`]. Implementors should not need to override this /// method. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// /// struct SecretlyOneHigher { @@ -1277,11 +1298,9 @@ pub trait Serializer: Sized { I: IntoIterator, ::Item: Serialize, { - let iter = iter.into_iter(); - let mut serializer = try!(self.serialize_seq(iterator_len_hint(&iter))); - for item in iter { - try!(serializer.serialize_element(&item)); - } + let mut iter = iter.into_iter(); + let mut serializer = tri!(self.serialize_seq(iterator_len_hint(&iter))); + tri!(iter.try_for_each(|item| serializer.serialize_element(&item))); serializer.end() } @@ -1291,7 +1310,7 @@ pub trait Serializer: Sized { /// using [`serialize_map`]. Implementors should not need to override this /// method. /// - /// ```edition2018 + /// ```edition2021 /// use serde::{Serialize, Serializer}; /// use std::collections::BTreeSet; /// @@ -1317,11 +1336,9 @@ pub trait Serializer: Sized { V: Serialize, I: IntoIterator, { - let iter = iter.into_iter(); - let mut serializer = try!(self.serialize_map(iterator_len_hint(&iter))); - for (key, value) in iter { - try!(serializer.serialize_entry(&key, &value)); - } + let mut iter = iter.into_iter(); + let mut serializer = tri!(self.serialize_map(iterator_len_hint(&iter))); + tri!(iter.try_for_each(|(key, value)| serializer.serialize_entry(&key, &value))); serializer.end() } @@ -1331,7 +1348,7 @@ pub trait Serializer: Sized { /// delegates to [`serialize_str`]. Serializers are encouraged to provide a /// more efficient implementation if possible. /// - /// ```edition2018 + /// ```edition2021 /// # struct DateTime; /// # /// # impl DateTime { @@ -1346,19 +1363,16 @@ pub trait Serializer: Sized { /// where /// S: Serializer, /// { - /// serializer.collect_str(&format_args!("{:?}{:?}", - /// self.naive_local(), - /// self.offset())) + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) /// } /// } /// ``` /// - /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html - /// [`serialize_str`]: #tymethod.serialize_str + /// [`serialize_str`]: Self::serialize_str #[cfg(any(feature = "std", feature = "alloc"))] - fn collect_str(self, value: &T) -> Result + fn collect_str(self, value: &T) -> Result where - T: Display, + T: ?Sized + Display, { self.serialize_str(&value.to_string()) } @@ -1369,7 +1383,7 @@ pub trait Serializer: Sized { /// of this method. If no more sensible behavior is possible, the /// implementation is expected to return an error. /// - /// ```edition2018 + /// ```edition2021 /// # struct DateTime; /// # /// # impl DateTime { @@ -1384,16 +1398,14 @@ pub trait Serializer: Sized { /// where /// S: Serializer, /// { - /// serializer.collect_str(&format_args!("{:?}{:?}", - /// self.naive_local(), - /// self.offset())) + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) /// } /// } /// ``` #[cfg(not(any(feature = "std", feature = "alloc")))] - fn collect_str(self, value: &T) -> Result + fn collect_str(self, value: &T) -> Result where - T: Display; + T: ?Sized + Display; /// Determine whether `Serialize` implementations should serialize in /// human-readable form. @@ -1401,10 +1413,10 @@ pub trait Serializer: Sized { /// Some types have a human-readable form that may be somewhat expensive to /// construct, as well as a binary form that is compact and efficient. /// Generally text-based formats like JSON and YAML will prefer to use the - /// human-readable one and binary formats like Bincode will prefer the + /// human-readable one and binary formats like Postcard will prefer the /// compact one. /// - /// ```edition2018 + /// ```edition2021 /// # use std::fmt::{self, Display}; /// # /// # struct Timestamp; @@ -1453,7 +1465,7 @@ pub trait Serializer: Sized { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// # use std::marker::PhantomData; /// # /// # struct Vec(PhantomData); @@ -1466,13 +1478,13 @@ pub trait Serializer: Sized { /// # /// # impl<'a, T> IntoIterator for &'a Vec { /// # type Item = &'a T; -/// # type IntoIter = Box>; +/// # type IntoIter = Box>; /// # fn into_iter(self) -> Self::IntoIter { /// # unimplemented!() /// # } /// # } /// # -/// use serde::ser::{Serialize, Serializer, SerializeSeq}; +/// use serde::ser::{Serialize, SerializeSeq, Serializer}; /// /// impl Serialize for Vec /// where @@ -1497,6 +1509,12 @@ pub trait Serializer: Sized { /// implementation of `SerializeSeq` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeSeq` is not satisfied", + ) +)] pub trait SerializeSeq { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1505,9 +1523,9 @@ pub trait SerializeSeq { type Error: Error; /// Serialize a sequence element. - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a sequence. fn end(self) -> Result; @@ -1517,8 +1535,8 @@ pub trait SerializeSeq { /// /// # Example use /// -/// ```edition2018 -/// use serde::ser::{Serialize, Serializer, SerializeTuple}; +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; /// /// # mod fool { /// # trait Serialize {} @@ -1547,7 +1565,7 @@ pub trait SerializeSeq { /// } /// ``` /// -/// ```edition2018 +/// ```edition2021 /// # use std::marker::PhantomData; /// # /// # struct Array(PhantomData); @@ -1560,13 +1578,13 @@ pub trait SerializeSeq { /// # /// # impl<'a, T> IntoIterator for &'a Array { /// # type Item = &'a T; -/// # type IntoIter = Box>; +/// # type IntoIter = Box>; /// # fn into_iter(self) -> Self::IntoIter { /// # unimplemented!() /// # } /// # } /// # -/// use serde::ser::{Serialize, Serializer, SerializeTuple}; +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; /// /// # mod fool { /// # trait Serialize {} @@ -1597,6 +1615,12 @@ pub trait SerializeSeq { /// implementation of `SerializeTuple` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeTuple` is not satisfied", + ) +)] pub trait SerializeTuple { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1605,9 +1629,9 @@ pub trait SerializeTuple { type Error: Error; /// Serialize a tuple element. - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple. fn end(self) -> Result; @@ -1617,7 +1641,7 @@ pub trait SerializeTuple { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; /// /// struct Rgb(u8, u8, u8); @@ -1642,6 +1666,12 @@ pub trait SerializeTuple { /// implementation of `SerializeTupleStruct` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeTupleStruct` is not satisfied", + ) +)] pub trait SerializeTupleStruct { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1650,9 +1680,9 @@ pub trait SerializeTupleStruct { type Error: Error; /// Serialize a tuple struct field. - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple struct. fn end(self) -> Result; @@ -1662,7 +1692,7 @@ pub trait SerializeTupleStruct { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; /// /// enum E { @@ -1700,6 +1730,12 @@ pub trait SerializeTupleStruct { /// implementation of `SerializeTupleVariant` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeTupleVariant` is not satisfied", + ) +)] pub trait SerializeTupleVariant { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1708,9 +1744,9 @@ pub trait SerializeTupleVariant { type Error: Error; /// Serialize a tuple variant field. - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Finish serializing a tuple variant. fn end(self) -> Result; @@ -1720,7 +1756,7 @@ pub trait SerializeTupleVariant { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// # use std::marker::PhantomData; /// # /// # struct HashMap(PhantomData, PhantomData); @@ -1733,14 +1769,14 @@ pub trait SerializeTupleVariant { /// # /// # impl<'a, K, V> IntoIterator for &'a HashMap { /// # type Item = (&'a K, &'a V); -/// # type IntoIter = Box>; +/// # type IntoIter = Box>; /// # /// # fn into_iter(self) -> Self::IntoIter { /// # unimplemented!() /// # } /// # } /// # -/// use serde::ser::{Serialize, Serializer, SerializeMap}; +/// use serde::ser::{Serialize, SerializeMap, Serializer}; /// /// impl Serialize for HashMap /// where @@ -1766,6 +1802,12 @@ pub trait SerializeTupleVariant { /// implementation of `SerializeMap` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeMap` is not satisfied", + ) +)] pub trait SerializeMap { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1779,9 +1821,9 @@ pub trait SerializeMap { /// `serialize_entry` instead as it may be implemented more efficiently in /// some formats compared to a pair of calls to `serialize_key` and /// `serialize_value`. - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a map value. /// @@ -1789,9 +1831,9 @@ pub trait SerializeMap { /// /// Calling `serialize_value` before `serialize_key` is incorrect and is /// allowed to panic or produce bogus results. - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Serialize a map entry consisting of a key and a value. /// @@ -1807,19 +1849,15 @@ pub trait SerializeMap { /// care about performance or are not able to optimize `serialize_entry` any /// better than this. /// - /// [`Serialize`]: ../trait.Serialize.html - /// [`serialize_key`]: #tymethod.serialize_key - /// [`serialize_value`]: #tymethod.serialize_value - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), Self::Error> + /// [`Serialize`]: crate::Serialize + /// [`serialize_key`]: Self::serialize_key + /// [`serialize_value`]: Self::serialize_value + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> where - K: Serialize, - V: Serialize, + K: ?Sized + Serialize, + V: ?Sized + Serialize, { - try!(self.serialize_key(key)); + tri!(self.serialize_key(key)); self.serialize_value(value) } @@ -1831,7 +1869,7 @@ pub trait SerializeMap { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// use serde::ser::{Serialize, SerializeStruct, Serializer}; /// /// struct Rgb { @@ -1860,6 +1898,12 @@ pub trait SerializeMap { /// implementation of `SerializeStruct` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeStruct` is not satisfied", + ) +)] pub trait SerializeStruct { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1868,15 +1912,13 @@ pub trait SerializeStruct { type Error: Error; /// Serialize a struct field. - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Indicate that a struct field has been skipped. + /// + /// The default implementation does nothing. #[inline] fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; @@ -1891,7 +1933,7 @@ pub trait SerializeStruct { /// /// # Example use /// -/// ```edition2018 +/// ```edition2021 /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; /// /// enum E { @@ -1926,6 +1968,12 @@ pub trait SerializeStruct { /// implementation of `SerializeStructVariant` for a basic JSON data format. /// /// [example data format]: https://serde.rs/data-format.html +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "the trait bound `{Self}: serde::ser::SerializeStructVariant` is not satisfied", + ) +)] pub trait SerializeStructVariant { /// Must match the `Ok` type of our `Serializer`. type Ok; @@ -1934,15 +1982,13 @@ pub trait SerializeStructVariant { type Error: Error; /// Serialize a struct variant field. - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where - T: Serialize; + T: ?Sized + Serialize; /// Indicate that a struct variant field has been skipped. + /// + /// The default implementation does nothing. #[inline] fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; diff --git a/serde/src/std_error.rs b/serde_core/src/std_error.rs similarity index 89% rename from serde/src/std_error.rs rename to serde_core/src/std_error.rs index 1055e0ffb..e026ace10 100644 --- a/serde/src/std_error.rs +++ b/serde_core/src/std_error.rs @@ -1,4 +1,4 @@ -use lib::{Debug, Display}; +use crate::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. @@ -9,7 +9,7 @@ use lib::{Debug, Display}; /// generally provide their error types with a `std::error::Error` impl /// directly: /// -/// ```edition2018 +/// ```edition2021 /// #[derive(Debug)] /// struct MySerError {...} /// @@ -29,7 +29,7 @@ use lib::{Debug, Display}; /// std = ["serde/std"] /// ``` /// -/// ```edition2018 +/// ```edition2021 /// #[cfg(feature = "std")] /// impl std::error::Error for MySerError {} /// ``` @@ -37,12 +37,12 @@ use lib::{Debug, Display}; /// ... or else provide the std Error impl unconditionally via Serde's /// re-export: /// -/// ```edition2018 +/// ```edition2021 /// impl serde::ser::StdError for MySerError {} /// ``` pub trait Error: Debug + Display { /// The underlying cause of this error, if any. - fn source(&self) -> Option<&(Error + 'static)> { + fn source(&self) -> Option<&(dyn Error + 'static)> { None } } diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index ed08716c2..0ec977406 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -1,15 +1,18 @@ [package] name = "serde_derive" -version = "1.0.118" # remember to update html_root_url +version = "1.0.228" authors = ["Erick Tryzelaar ", "David Tolnay "] -license = "MIT OR Apache-2.0" +categories = ["no-std", "no-std::no-alloc"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" -homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" documentation = "https://serde.rs/derive.html" -keywords = ["serde", "serialization", "no_std"] +edition = "2021" +exclude = ["build.rs"] +homepage = "https://serde.rs" +keywords = ["serde", "serialization", "no_std", "derive"] +license = "MIT OR Apache-2.0" readme = "crates-io.md" -include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +repository = "https://github.com/serde-rs/serde" +rust-version = "1.68" [features] default = [] @@ -20,12 +23,20 @@ name = "serde_derive" proc-macro = true [dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "1.0.33", features = ["visit"] } +proc-macro2 = { workspace = true, features = ["proc-macro"] } +quote = { workspace = true, features = ["proc-macro"] } +syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] } [dev-dependencies] -serde = { version = "1.0", path = "../serde" } +serde = { version = "1", path = "../serde" } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", + "--extern-html-root-url=proc_macro=https://doc.rust-lang.org", +] diff --git a/serde_derive/build.rs b/serde_derive/build.rs index 6e1b7b6dd..ebaa409a4 100644 --- a/serde_derive/build.rs +++ b/serde_derive/build.rs @@ -1,30 +1,8 @@ -use std::env; -use std::process::Command; -use std::str; - -// The rustc-cfg strings below are *not* public API. Please let us know by -// opening a GitHub issue if your build environment requires some way to enable -// these cfgs other than by executing our build script. fn main() { - let minor = match rustc_minor_version() { - Some(minor) => minor, - None => return, - }; - - // Underscore const names stabilized in Rust 1.37: - // https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros - if minor >= 37 { - println!("cargo:rustc-cfg=underscore_consts"); - } -} + // Warning: build.rs is not published to crates.io. -fn rustc_minor_version() -> Option { - let rustc = env::var_os("RUSTC")?; - let output = Command::new(rustc).arg("--version").output().ok()?; - let version = str::from_utf8(&output.stdout).ok()?; - let mut pieces = version.split('.'); - if pieces.next() != Some("rustc 1") { - return None; - } - pieces.next()?.parse().ok() + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-cfg=check_cfg"); + println!("cargo:rustc-check-cfg=cfg(check_cfg)"); + println!("cargo:rustc-check-cfg=cfg(exhaustive)"); } diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs index ec2eafe89..2ff6521fe 100644 --- a/serde_derive/src/bound.rs +++ b/serde_derive/src/bound.rs @@ -1,13 +1,9 @@ +use crate::internals::ast::{Container, Data}; +use crate::internals::{attr, ungroup}; +use proc_macro2::Span; use std::collections::HashSet; - -use syn; use syn::punctuated::{Pair, Punctuated}; -use syn::visit::{self, Visit}; - -use internals::ast::{Container, Data}; -use internals::{attr, ungroup}; - -use proc_macro2::Span; +use syn::Token; // Remove the default from every type parameter because in the generated impls // they look like associated types: "error: associated type bindings are not @@ -50,8 +46,8 @@ pub fn with_where_predicates_from_fields( let predicates = cont .data .all_fields() - .flat_map(|field| from_field(&field.attrs)) - .flat_map(|predicates| predicates.to_vec()); + .filter_map(|field| from_field(&field.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); let mut generics = generics.clone(); generics.make_where_clause().predicates.extend(predicates); @@ -72,8 +68,8 @@ pub fn with_where_predicates_from_variants( let predicates = variants .iter() - .flat_map(|variant| from_variant(&variant.attrs)) - .flat_map(|predicates| predicates.to_vec()); + .filter_map(|variant| from_variant(&variant.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); let mut generics = generics.clone(); generics.make_where_clause().predicates.extend(predicates); @@ -112,7 +108,8 @@ pub fn with_bound( // parameters. associated_type_usage: Vec<&'ast syn::TypePath>, } - impl<'ast> Visit<'ast> for FindTyParams<'ast> { + + impl<'ast> FindTyParams<'ast> { fn visit_field(&mut self, field: &'ast syn::Field) { if let syn::Type::Path(ty) = ungroup(&field.ty) { if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() { @@ -138,7 +135,103 @@ pub fn with_bound( self.relevant_type_params.insert(id.clone()); } } - visit::visit_path(self, path); + for segment in &path.segments { + self.visit_path_segment(segment); + } + } + + // Everything below is simply traversing the syntax tree. + + fn visit_type(&mut self, ty: &'ast syn::Type) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::Type::Array(ty) => self.visit_type(&ty.elem), + syn::Type::BareFn(ty) => { + for arg in &ty.inputs { + self.visit_type(&arg.ty); + } + self.visit_return_type(&ty.output); + } + syn::Type::Group(ty) => self.visit_type(&ty.elem), + syn::Type::ImplTrait(ty) => { + for bound in &ty.bounds { + self.visit_type_param_bound(bound); + } + } + syn::Type::Macro(ty) => self.visit_macro(&ty.mac), + syn::Type::Paren(ty) => self.visit_type(&ty.elem), + syn::Type::Path(ty) => { + if let Some(qself) = &ty.qself { + self.visit_type(&qself.ty); + } + self.visit_path(&ty.path); + } + syn::Type::Ptr(ty) => self.visit_type(&ty.elem), + syn::Type::Reference(ty) => self.visit_type(&ty.elem), + syn::Type::Slice(ty) => self.visit_type(&ty.elem), + syn::Type::TraitObject(ty) => { + for bound in &ty.bounds { + self.visit_type_param_bound(bound); + } + } + syn::Type::Tuple(ty) => { + for elem in &ty.elems { + self.visit_type(elem); + } + } + + syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {} + + _ => {} + } + } + + fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) { + self.visit_path_arguments(&segment.arguments); + } + + fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) { + match arguments { + syn::PathArguments::None => {} + syn::PathArguments::AngleBracketed(arguments) => { + for arg in &arguments.args { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::GenericArgument::Type(arg) => self.visit_type(arg), + syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty), + syn::GenericArgument::Lifetime(_) + | syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) => {} + _ => {} + } + } + } + syn::PathArguments::Parenthesized(arguments) => { + for argument in &arguments.inputs { + self.visit_type(argument); + } + self.visit_return_type(&arguments.output); + } + } + } + + fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) { + match return_type { + syn::ReturnType::Default => {} + syn::ReturnType::Type(_, output) => self.visit_type(output), + } + } + + fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) { + match bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path), + syn::TypeParamBound::Lifetime(_) + | syn::TypeParamBound::PreciseCapture(_) + | syn::TypeParamBound::Verbatim(_) => {} + _ => {} + } } // Type parameter should not be considered used by a macro path. @@ -162,7 +255,7 @@ pub fn with_bound( }; match &cont.data { Data::Enum(variants) => { - for variant in variants.iter() { + for variant in variants { let relevant_fields = variant .fields .iter() @@ -245,7 +338,7 @@ pub fn with_self_bound( pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { let bound = syn::Lifetime::new(lifetime, Span::call_site()); - let def = syn::LifetimeDef { + let def = syn::LifetimeParam { attrs: Vec::new(), lifetime: bound.clone(), colon_token: None, diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 55ab808bc..38408e9f1 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1,43 +1,55 @@ -use proc_macro2::{Literal, Span, TokenStream}; -use quote::ToTokens; +use crate::deprecated::allow_deprecated; +use crate::fragment::{Expr, Fragment, Stmts}; +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::name::Name; +use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; +use crate::{bound, dummy, pretend, private, this}; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned, ToTokens}; +use std::collections::BTreeSet; +use std::ptr; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::{self, Ident, Index, Member}; +use syn::{parse_quote, Ident, Index, Member}; -use bound; -use dummy; -use fragment::{Expr, Fragment, Match, Stmts}; -use internals::ast::{Container, Data, Field, Style, Variant}; -use internals::{attr, ungroup, Ctxt, Derive}; -use pretend; +mod enum_; +mod enum_adjacently; +mod enum_externally; +mod enum_internally; +mod enum_untagged; +mod identifier; +mod struct_; +mod tuple; +mod unit; -use std::collections::BTreeSet; -use std::ptr; +pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { + replace_receiver(input); -pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result> { let ctxt = Ctxt::new(); - let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) { - Some(cont) => cont, - None => return Err(ctxt.check().unwrap_err()), + let Some(cont) = Container::from_ast(&ctxt, input, Derive::Deserialize, &private.ident()) + else { + return Err(ctxt.check().unwrap_err()); }; precondition(&ctxt, &cont); ctxt.check()?; let ident = &cont.ident; let params = Parameters::new(&cont); - let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms); + let (de_impl_generics, _, ty_generics, where_clause) = params.generics_with_de_lifetime(); let body = Stmts(deserialize_body(&cont, ¶ms)); let delife = params.borrowed.de_lifetime(); - let serde = cont.attrs.serde_path(); + let allow_deprecated = allow_deprecated(input); let impl_block = if let Some(remote) = cont.attrs.remote() { let vis = &input.vis; - let used = pretend::pretend_used(&cont); + let used = pretend::pretend_used(&cont, params.is_packed); quote! { + #[automatically_derived] + #allow_deprecated impl #de_impl_generics #ident #ty_generics #where_clause { - #vis fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result<#remote #ty_generics, __D::Error> + #vis fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result<#remote #ty_generics, __D::Error> where - __D: #serde::Deserializer<#delife>, + __D: _serde::Deserializer<#delife>, { #used #body @@ -49,10 +61,11 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result for #ident #ty_generics #where_clause { - fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result + #allow_deprecated + impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause { + fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result where - __D: #serde::Deserializer<#delife>, + __D: _serde::Deserializer<#delife>, { #body } @@ -64,8 +77,6 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result` for generic parameters for use in + /// expression position. + this_value: syn::Path, /// Generics including any explicit and inferred bounds for the impl. generics: syn::Generics, @@ -121,32 +136,53 @@ struct Parameters { /// At least one field has a serde(getter) attribute, implying that the /// remote type has a private field. has_getter: bool, + + /// Type has a repr(packed) attribute. + is_packed: bool, } impl Parameters { fn new(cont: &Container) -> Self { let local = cont.ident.clone(); - let this = match cont.attrs.remote() { - Some(remote) => remote.clone(), - None => cont.ident.clone().into(), - }; + let this_type = this::this_type(cont); + let this_value = this::this_value(cont); let borrowed = borrowed_lifetimes(cont); let generics = build_generics(cont, &borrowed); let has_getter = cont.data.has_getter(); + let is_packed = cont.attrs.is_packed(); Parameters { local, - this, + this_type, + this_value, generics, borrowed, has_getter, + is_packed, } } /// Type name to use in error messages and `&'static str` arguments to /// various Deserializer methods. fn type_name(&self) -> String { - self.this.segments.last().unwrap().ident.to_string() + self.this_type.segments.last().unwrap().ident.to_string() + } + + /// Split the data structure's generics into the pieces to use for its + /// `Deserialize` impl, augmented with an additional `'de` lifetime for use + /// as the `Deserialize` trait's lifetime. + fn generics_with_de_lifetime( + &self, + ) -> ( + DeImplGenerics, + DeTypeGenerics, + syn::TypeGenerics, + Option<&syn::WhereClause>, + ) { + let de_impl_generics = DeImplGenerics(self); + let de_ty_generics = DeTypeGenerics(self); + let (_, ty_generics, where_clause) = self.generics.split_for_impl(); + (de_impl_generics, de_ty_generics, ty_generics, where_clause) } } @@ -165,9 +201,11 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi Some(predicates) => bound::with_where_predicates(&generics, predicates), None => { let generics = match *cont.attrs.default() { - attr::Default::Default => { - bound::with_self_bound(cont, &generics, &parse_quote!(_serde::export::Default)) - } + attr::Default::Default => bound::with_self_bound( + cont, + &generics, + &parse_quote!(_serde::#private::Default), + ), attr::Default::None | attr::Default::Path(_) => generics, }; @@ -183,7 +221,7 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi cont, &generics, requires_default, - &parse_quote!(_serde::export::Default), + &parse_quote!(_serde::#private::Default), ) } } @@ -229,9 +267,9 @@ impl BorrowedLifetimes { } } - fn de_lifetime_def(&self) -> Option { + fn de_lifetime_param(&self) -> Option { match self { - BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeDef { + BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'de", Span::call_site()), colon_token: None, @@ -274,18 +312,18 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { deserialize_try_from(type_try_from) } else if let attr::Identifier::No = cont.attrs.identifier() { match &cont.data { - Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs), + Data::Enum(variants) => enum_::deserialize(params, variants, &cont.attrs), Data::Struct(Style::Struct, fields) => { - deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) + struct_::deserialize(params, fields, &cont.attrs, StructForm::Struct) } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { - deserialize_tuple(None, params, fields, &cont.attrs, None) + tuple::deserialize(params, fields, &cont.attrs, TupleForm::Tuple) } - Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), + Data::Struct(Style::Unit, _) => unit::deserialize(params, &cont.attrs), } } else { match &cont.data { - Data::Enum(variants) => deserialize_custom_identifier(params, variants, &cont.attrs), + Data::Enum(variants) => identifier::deserialize_custom(params, variants, &cont.attrs), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), } } @@ -311,10 +349,10 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { - deserialize_struct_in_place(None, params, fields, &cont.attrs, None)? + struct_::deserialize_in_place(params, fields, &cont.attrs)? } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { - deserialize_tuple_in_place(None, params, fields, &cont.attrs, None) + tuple::deserialize_in_place(params, fields, &cont.attrs) } Data::Enum(_) | Data::Struct(Style::Unit, _) => { return None; @@ -325,7 +363,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option(__deserializer: __D, __place: &mut Self) -> _serde::export::Result<(), __D::Error> + fn deserialize_in_place<__D>(__deserializer: __D, __place: &mut Self) -> _serde::#private::Result<(), __D::Error> where __D: _serde::Deserializer<#delife>, { @@ -341,13 +379,14 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option< None } +/// Generates `Deserialize::deserialize` body for a type with `#[serde(transparent)]` attribute fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let fields = match &cont.data { Data::Struct(_, fields) => fields, Data::Enum(_) => unreachable!(), }; - let this = ¶ms.this; + let this_value = ¶ms.this_value; let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); let path = match transparent_field.attrs.deserialize_with() { @@ -364,252 +403,49 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { quote!(#member: __transparent) } else { let value = match field.attrs.default() { - attr::Default::Default => quote!(_serde::export::Default::default()), - attr::Default::Path(path) => quote!(#path()), - attr::Default::None => quote!(_serde::export::PhantomData), + attr::Default::Default => quote!(_serde::#private::Default::default()), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => quote_spanned!(path.span()=> #path()), + attr::Default::None => quote!(_serde::#private::PhantomData), }; quote!(#member: #value) } }); quote_block! { - _serde::export::Result::map( + _serde::#private::Result::map( #path(__deserializer), - |__transparent| #this { #(#assign),* }) + |__transparent| #this_value { #(#assign),* }) } } +/// Generates `Deserialize::deserialize` body for a type with `#[serde(from)]` attribute fn deserialize_from(type_from: &syn::Type) -> Fragment { quote_block! { - _serde::export::Result::map( + _serde::#private::Result::map( <#type_from as _serde::Deserialize>::deserialize(__deserializer), - _serde::export::From::from) + _serde::#private::From::from) } } +/// Generates `Deserialize::deserialize` body for a type with `#[serde(try_from)]` attribute fn deserialize_try_from(type_try_from: &syn::Type) -> Fragment { quote_block! { - _serde::export::Result::and_then( + _serde::#private::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 { - let this = ¶ms.this; - let type_name = cattrs.name().deserialize_name(); - - let expecting = format!("unit struct {}", params.type_name()); - - quote_block! { - struct __Visitor; - - impl<'de> _serde::de::Visitor<'de> for __Visitor { - type Value = #this; - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #[inline] - fn visit_unit<__E>(self) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(#this) - } - } - - _serde::Deserializer::deserialize_unit_struct(__deserializer, #type_name, __Visitor) - } -} - -fn deserialize_tuple( - variant_ident: Option<&syn::Ident>, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - deserializer: Option, -) -> Fragment { - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - - assert!(!cattrs.has_flatten()); - - // If there are getters (implying private fields), construct the local type - // and use an `Into` conversion to get the remote type. If there are no - // getters then construct the target type directly. - let construct = if params.has_getter { - let local = ¶ms.local; - quote!(#local) - } else { - quote!(#this) - }; - - let is_enum = variant_ident.is_some(); - let type_path = match variant_ident { - Some(variant_ident) => quote!(#construct::#variant_ident), - None => construct, - }; - let expecting = match variant_ident { - Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), - None => format!("tuple struct {}", params.type_name()), - }; - - let nfields = fields.len(); - - let visit_newtype_struct = if !is_enum && nfields == 1 { - Some(deserialize_newtype_struct(&type_path, params, &fields[0])) - } else { - None - }; - - let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, false, cattrs, &expecting, - )); - - let visitor_expr = quote! { - __Visitor { - marker: _serde::export::PhantomData::<#this #ty_generics>, - lifetime: _serde::export::PhantomData, - } - }; - let dispatch = if let Some(deserializer) = deserializer { - quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) - } else if is_enum { - quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) - } else if nfields == 1 { - let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) - } else { - let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { - quote!(_) - } else { - quote!(mut __seq) - }; - - quote_block! { - struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #visit_newtype_struct - - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - } - - #dispatch + |v| _serde::#private::TryFrom::try_from(v).map_err(_serde::de::Error::custom)) } } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_tuple_in_place( - variant_ident: Option, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - deserializer: Option, -) -> Fragment { - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - - assert!(!cattrs.has_flatten()); - - let is_enum = variant_ident.is_some(); - let expecting = match variant_ident { - Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), - None => format!("tuple struct {}", params.type_name()), - }; - - let nfields = fields.len(); - - let visit_newtype_struct = if !is_enum && nfields == 1 { - Some(deserialize_newtype_struct_in_place(params, &fields[0])) - } else { - None - }; - - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); - - let visitor_expr = quote! { - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - } - }; - - let dispatch = if let Some(deserializer) = deserializer { - quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) - } else if is_enum { - quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) - } else if nfields == 1 { - let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) - } else { - let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { - quote!(_) - } else { - quote!(mut __seq) - }; - - let in_place_impl_generics = de_impl_generics.in_place(); - let in_place_ty_generics = de_ty_generics.in_place(); - let place_life = place_lifetime(); - - quote_block! { - struct __Visitor #in_place_impl_generics #where_clause { - place: &#place_life mut #this #ty_generics, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { - type Value = (); - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #visit_newtype_struct - - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - } - - #dispatch - } +enum TupleForm<'a> { + Tuple, + /// Contains a variant name + ExternallyTagged(&'a syn::Ident), + /// Contains a variant name + Untagged(&'a syn::Ident), } fn deserialize_seq( @@ -631,6 +467,7 @@ fn deserialize_seq( } else { format!("{} with {} elements", expecting, deserialized_count) }; + let expecting = cattrs.expecting().unwrap_or(&expecting); let mut index_in_seq = 0_usize; let let_values = vars.clone().zip(fields).map(|(var, field)| { @@ -646,31 +483,23 @@ fn deserialize_seq( let span = field.original.span(); let func = quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>); - quote!(try!(#func(&mut __seq))) + quote!(#func(&mut __seq)?) } Some(path) => { let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); quote!({ #wrapper - _serde::export::Option::map( - try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)), + _serde::#private::Option::map( + _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)?, |__wrap| __wrap.value) }) } }; - let value_if_none = match field.attrs.default() { - attr::Default::Default => quote!(_serde::export::Default::default()), - attr::Default::Path(path) => quote!(#path()), - attr::Default::None => quote!( - return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); - ), - }; + let value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting); let assign = quote! { let #var = match #visit { - _serde::export::Some(__value) => __value, - _serde::export::None => { - #value_if_none - } + _serde::#private::Some(__value) => __value, + _serde::#private::None => #value_if_none, }; }; index_in_seq += 1; @@ -690,17 +519,22 @@ fn deserialize_seq( }; if params.has_getter { - let this = ¶ms.this; + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); result = quote! { - _serde::export::Into::<#this>::into(#result) + _serde::#private::Into::<#this_type #ty_generics>::into(#result) }; } let let_default = match cattrs.default() { attr::Default::Default => Some(quote!( - let __default: Self::Value = _serde::export::Default::default(); + let __default: Self::Value = _serde::#private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> let __default: Self::Value = #path(); )), attr::Default::None => { @@ -713,7 +547,7 @@ fn deserialize_seq( quote_block! { #let_default #(#let_values)* - _serde::export::Ok(#result) + _serde::#private::Ok(#result) } } @@ -733,6 +567,7 @@ fn deserialize_seq_in_place( } else { format!("{} with {} elements", expecting, deserialized_count) }; + let expecting = cattrs.expecting().unwrap_or(&expecting); let mut index_in_seq = 0usize; let write_values = fields.iter().map(|field| { @@ -744,24 +579,14 @@ fn deserialize_seq_in_place( self.place.#member = #default; } } else { - let value_if_none = match field.attrs.default() { - attr::Default::Default => quote!( - self.place.#member = _serde::export::Default::default(); - ), - attr::Default::Path(path) => quote!( - self.place.#member = #path(); - ), - attr::Default::None => quote!( - return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); - ), - }; + let value_if_none = expr_is_missing_seq(Some(quote!(self.place.#member = )), index_in_seq, field, cattrs, expecting); let write = match field.attrs.deserialize_with() { None => { quote! { - if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.#member))) + if let _serde::#private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq, + _serde::#private::de::InPlaceSeed(&mut self.place.#member))? { - #value_if_none + #value_if_none; } } } @@ -769,12 +594,15 @@ fn deserialize_seq_in_place( let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); quote!({ #wrapper - match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) { - _serde::export::Some(__wrap) => { + match _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq) { + _serde::#private::Ok(_serde::#private::Some(__wrap)) => { self.place.#member = __wrap.value; } - _serde::export::None => { - #value_if_none + _serde::#private::Ok(_serde::#private::None) => { + #value_if_none; + } + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); } } }) @@ -785,14 +613,18 @@ fn deserialize_seq_in_place( } }); - let this = ¶ms.this; + let this_type = ¶ms.this_type; let (_, ty_generics, _) = params.generics.split_for_impl(); let let_default = match cattrs.default() { attr::Default::Default => Some(quote!( - let __default: #this #ty_generics = _serde::export::Default::default(); + let __default: #this_type #ty_generics = _serde::#private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( - let __default: #this #ty_generics = #path(); + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> + let __default: #this_type #ty_generics = #path(); )), attr::Default::None => { // We don't need the default value, to prevent an unused variable warning @@ -804,2074 +636,146 @@ fn deserialize_seq_in_place( quote_block! { #let_default #(#write_values)* - _serde::export::Ok(()) + _serde::#private::Ok(()) } } -fn deserialize_newtype_struct( - type_path: &TokenStream, - params: &Parameters, - field: &Field, -) -> TokenStream { - let delife = params.borrowed.de_lifetime(); - let field_ty = field.ty; - - let value = match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); - quote! { - try!(#func(__e)) - } - } - Some(path) => { - quote! { - try!(#path(__e)) - } - } - }; - - let mut result = quote!(#type_path(__field0)); - if params.has_getter { - let this = ¶ms.this; - result = quote! { - _serde::export::Into::<#this>::into(#result) - }; - } - - quote! { - #[inline] - fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result - where - __E: _serde::Deserializer<#delife>, - { - let __field0: #field_ty = #value; - _serde::export::Ok(#result) - } - } +enum StructForm<'a> { + Struct, + /// Contains a variant name + ExternallyTagged(&'a syn::Ident), + /// Contains a variant name + InternallyTagged(&'a syn::Ident), + /// Contains a variant name + Untagged(&'a syn::Ident), } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> TokenStream { - // We do not generate deserialize_in_place if every field has a - // deserialize_with. - assert!(field.attrs.deserialize_with().is_none()); - - let delife = params.borrowed.de_lifetime(); - - quote! { - #[inline] - fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result - where - __E: _serde::Deserializer<#delife>, - { - _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) - } - } +struct FieldWithAliases<'a> { + ident: Ident, + aliases: &'a BTreeSet, } -enum Untagged { - Yes, - No, +fn field_i(i: usize) -> Ident { + Ident::new(&format!("__field{}", i), Span::call_site()) } -fn deserialize_struct( - variant_ident: Option<&syn::Ident>, +/// This function wraps the expression in `#[serde(deserialize_with = "...")]` +/// in a trait to prevent it from accessing the internal `Deserialize` state. +fn wrap_deserialize_with( params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - deserializer: Option, - untagged: &Untagged, -) -> Fragment { - let is_enum = variant_ident.is_some(); - - let this = ¶ms.this; + value_ty: &TokenStream, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + let this_type = ¶ms.this_type; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + params.generics_with_de_lifetime(); let delife = params.borrowed.de_lifetime(); + let deserializer_var = quote!(__deserializer); - // If there are getters (implying private fields), construct the local type - // and use an `Into` conversion to get the remote type. If there are no - // getters then construct the target type directly. - let construct = if params.has_getter { - let local = ¶ms.local; - quote!(#local) - } else { - quote!(#this) - }; - - let type_path = match variant_ident { - Some(variant_ident) => quote!(#construct::#variant_ident), - None => construct, - }; - let expecting = match variant_ident { - Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), - None => format!("struct {}", params.type_name()), - }; - - let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, true, cattrs, &expecting, - )); - - let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() { - deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs) - } else { - deserialize_struct_as_struct_visitor(&type_path, params, fields, cattrs) - }; - let field_visitor = Stmts(field_visitor); - let fields_stmt = fields_stmt.map(Stmts); - let visit_map = Stmts(visit_map); - - let visitor_expr = quote! { - __Visitor { - marker: _serde::export::PhantomData::<#this #ty_generics>, - lifetime: _serde::export::PhantomData, - } - }; - let dispatch = if let Some(deserializer) = deserializer { - quote! { - _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) - } - } else if is_enum && cattrs.has_flatten() { - quote! { - _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) - } - } else if is_enum { - quote! { - _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) - } - } else if cattrs.has_flatten() { - quote! { - _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) - } - } else { - let type_name = cattrs.name().deserialize_name(); - quote! { - _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) - } - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { - quote!(_) - } else { - quote!(mut __seq) - }; - - // untagged struct variants do not get a visit_seq method. The same applies to - // structs that only have a map representation. - let visit_seq = match *untagged { - Untagged::No if !cattrs.has_flatten() => Some(quote! { - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - }), - _ => None, - }; - - let visitor_seed = if is_enum && cattrs.has_flatten() { - Some(quote! { - impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_map(__deserializer, self) - } - } - }) - } else { - None + // If #deserialize_with returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(with = "...")] + // ^^^^^ + let value = quote_spanned! {deserialize_with.span()=> + #deserialize_with(#deserializer_var)? }; - - quote_block! { - #field_visitor - - struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, + let wrapper = quote! { + #[doc(hidden)] + struct __DeserializeWith #de_impl_generics #where_clause { + value: #value_ty, + phantom: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, } - impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #visit_seq - - #[inline] - fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result + #[automatically_derived] + impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause { + fn deserialize<__D>(#deserializer_var: __D) -> _serde::#private::Result where - __A: _serde::de::MapAccess<#delife>, + __D: _serde::Deserializer<#delife>, { - #visit_map + _serde::#private::Ok(__DeserializeWith { + value: #value, + phantom: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + }) } } + }; - #visitor_seed - - #fields_stmt + let wrapper_ty = quote!(__DeserializeWith #de_ty_generics); - #dispatch - } + (wrapper, wrapper_ty) } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_struct_in_place( - variant_ident: Option, +fn wrap_deserialize_field_with( params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - deserializer: Option, -) -> Option { - let is_enum = variant_ident.is_some(); - - // for now we do not support in_place deserialization for structs that - // are represented as map. - if cattrs.has_flatten() { - return None; - } + field_ty: &syn::Type, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + wrap_deserialize_with(params, "e!(#field_ty), deserialize_with) +} - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); +// Generates closure that converts single input parameter to the final value. +fn unwrap_to_variant_closure( + params: &Parameters, + variant: &Variant, + with_wrapper: bool, +) -> TokenStream { + let this_value = ¶ms.this_value; + let variant_ident = &variant.ident; - let expecting = match variant_ident { - Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), - None => format!("struct {}", params.type_name()), + let (arg, wrapper) = if with_wrapper { + (quote! { __wrap }, quote! { __wrap.value }) + } else { + let field_tys = variant.fields.iter().map(|field| field.ty); + (quote! { __wrap: (#(#field_tys),*) }, quote! { __wrap }) }; - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); - - let (field_visitor, fields_stmt, visit_map) = - deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs); - - let field_visitor = Stmts(field_visitor); - let fields_stmt = Stmts(fields_stmt); - let visit_map = Stmts(visit_map); + let field_access = (0..variant.fields.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); - let visitor_expr = quote! { - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, + match variant.style { + Style::Struct if variant.fields.len() == 1 => { + let member = &variant.fields[0].member; + quote! { + |#arg| #this_value::#variant_ident { #member: #wrapper } + } } - }; - let dispatch = if let Some(deserializer) = deserializer { - quote! { - _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) - } - } else if is_enum { - quote! { - _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) - } - } else { - let type_name = cattrs.name().deserialize_name(); - quote! { - _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) - } - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { - quote!(_) - } else { - quote!(mut __seq) - }; - - let visit_seq = quote! { - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - }; - - let in_place_impl_generics = de_impl_generics.in_place(); - let in_place_ty_generics = de_ty_generics.in_place(); - let place_life = place_lifetime(); - - Some(quote_block! { - #field_visitor - - struct __Visitor #in_place_impl_generics #where_clause { - place: &#place_life mut #this #ty_generics, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { - type Value = (); - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #visit_seq - - #[inline] - fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result - where - __A: _serde::de::MapAccess<#delife>, - { - #visit_map - } - } - - #fields_stmt - - #dispatch - }) -} - -fn deserialize_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - match cattrs.tag() { - attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), - attr::TagType::Internal { tag } => { - deserialize_internally_tagged_enum(params, variants, cattrs, tag) - } - attr::TagType::Adjacent { tag, content } => { - deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) - } - attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs), - } -} - -fn prepare_enum_variant_enum( - variants: &[Variant], - cattrs: &attr::Container, -) -> (TokenStream, Stmts) { - let mut deserialized_variants = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()); - - let variant_names_idents: Vec<_> = deserialized_variants - .clone() - .map(|(i, variant)| { - ( - variant.attrs.name().deserialize_name(), - field_i(i), - variant.attrs.aliases(), - ) - }) - .collect(); - - let other_idx = deserialized_variants.position(|(_, variant)| variant.attrs.other()); - - let variants_stmt = { - let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); - quote! { - const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; - } - }; - - let variant_visitor = Stmts(deserialize_generated_identifier( - &variant_names_idents, - cattrs, - true, - other_idx, - )); - - (variants_stmt, variant_visitor) -} - -fn deserialize_externally_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - - let type_name = cattrs.name().deserialize_name(); - let expecting = format!("enum {}", params.type_name()); - - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); - - // Match arms to extract a variant from a string - let variant_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_name = field_i(i); - - let block = Match(deserialize_externally_tagged_variant( - params, variant, cattrs, - )); - - quote! { - (__Field::#variant_name, __variant) => #block - } - }); - - let all_skipped = variants - .iter() - .all(|variant| variant.attrs.skip_deserializing()); - let match_variant = if all_skipped { - // This is an empty enum like `enum Impossible {}` or an enum in which - // all variants have `#[serde(skip_deserializing)]`. - quote! { - // FIXME: Once we drop support for Rust 1.15: - // let _serde::export::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); - // _serde::export::Err(__err) - _serde::export::Result::map( - _serde::de::EnumAccess::variant::<__Field>(__data), - |(__impossible, _)| match __impossible {}) - } - } else { - quote! { - match try!(_serde::de::EnumAccess::variant(__data)) { - #(#variant_arms)* - } - } - }; - - quote_block! { - #variant_visitor - - struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result - where - __A: _serde::de::EnumAccess<#delife>, - { - #match_variant - } - } - - #variants_stmt - - _serde::Deserializer::deserialize_enum( - __deserializer, - #type_name, - VARIANTS, - __Visitor { - marker: _serde::export::PhantomData::<#this #ty_generics>, - lifetime: _serde::export::PhantomData, - }, - ) - } -} - -fn deserialize_internally_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, - tag: &str, -) -> Fragment { - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); - - // Match arms to extract a variant from a string - let variant_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_name = field_i(i); - - let block = Match(deserialize_internally_tagged_variant( - params, - variant, - cattrs, - quote! { - _serde::private::de::ContentDeserializer::<__D::Error>::new(__tagged.content) - }, - )); - - quote! { - __Field::#variant_name => #block - } - }); - - quote_block! { - #variant_visitor - - #variants_stmt - - let __tagged = try!(_serde::Deserializer::deserialize_any( - __deserializer, - _serde::private::de::TaggedContentVisitor::<__Field>::new(#tag))); - - match __tagged.tag { - #(#variant_arms)* - } - } -} - -fn deserialize_adjacently_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, - tag: &str, - content: &str, -) -> Fragment { - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); - - let variant_arms: &Vec<_> = &variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_index = field_i(i); - - let block = Match(deserialize_untagged_variant( - params, - variant, - cattrs, - quote!(__deserializer), - )); - - quote! { - __Field::#variant_index => #block - } - }) - .collect(); - - let expecting = format!("adjacently tagged enum {}", params.type_name()); - let type_name = cattrs.name().deserialize_name(); - let deny_unknown_fields = cattrs.deny_unknown_fields(); - - // If unknown fields are allowed, we pick the visitor that can step over - // those. Otherwise we pick the visitor that fails on unknown keys. - let field_visitor_ty = if deny_unknown_fields { - quote! { _serde::private::de::TagOrContentFieldVisitor } - } else { - quote! { _serde::private::de::TagContentOtherFieldVisitor } - }; - - let tag_or_content = quote! { - #field_visitor_ty { - tag: #tag, - content: #content, - } - }; - - let mut missing_content = quote! { - _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) - }; - let mut missing_content_fallthrough = quote!(); - let missing_content_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .filter_map(|(i, variant)| { - let variant_index = field_i(i); - let variant_ident = &variant.ident; - - let arm = match variant.style { - Style::Unit => quote! { - _serde::export::Ok(#this::#variant_ident) - }, - Style::Newtype if variant.attrs.deserialize_with().is_none() => { - let span = variant.original.span(); - let func = quote_spanned!(span=> _serde::private::de::missing_field); - quote! { - #func(#content).map(#this::#variant_ident) - } - } - _ => { - missing_content_fallthrough = quote!(_ => #missing_content); - return None; - } - }; - Some(quote! { - __Field::#variant_index => #arm, - }) - }) - .collect::>(); - if !missing_content_arms.is_empty() { - missing_content = quote! { - match __field { - #(#missing_content_arms)* - #missing_content_fallthrough - } - }; - } - - // Advance the map by one key, returning early in case of error. - let next_key = quote! { - try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) - }; - - // When allowing unknown fields, we want to transparently step through keys - // we don't care about until we find `tag`, `content`, or run out of keys. - let next_relevant_key = if deny_unknown_fields { - next_key - } else { - quote!({ - let mut __rk : _serde::export::Option<_serde::private::de::TagOrContentField> = _serde::export::None; - while let _serde::export::Some(__k) = #next_key { - match __k { - _serde::private::de::TagContentOtherField::Other => { - try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); - continue; - }, - _serde::private::de::TagContentOtherField::Tag => { - __rk = _serde::export::Some(_serde::private::de::TagOrContentField::Tag); - break; - } - _serde::private::de::TagContentOtherField::Content => { - __rk = _serde::export::Some(_serde::private::de::TagOrContentField::Content); - break; - } - } - } - - __rk - }) - }; - - // Step through remaining keys, looking for duplicates of previously-seen - // keys. When unknown fields are denied, any key that isn't a duplicate will - // at this point immediately produce an error. - let visit_remaining_keys = quote! { - match #next_relevant_key { - _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { - _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) - } - _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { - _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) - } - _serde::export::None => _serde::export::Ok(__ret), - } - }; - - let finish_content_then_tag = if variant_arms.is_empty() { - quote! { - match try!(_serde::de::MapAccess::next_value::<__Field>(&mut __map)) {} - } - } else { - quote! { - let __ret = try!(match try!(_serde::de::MapAccess::next_value(&mut __map)) { - // Deserialize the buffered content now that we know the variant. - #(#variant_arms)* - }); - // Visit remaining keys, looking for duplicates. - #visit_remaining_keys - } - }; - - quote_block! { - #variant_visitor - - #variants_stmt - - struct __Seed #de_impl_generics #where_clause { - field: __Field, - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<#delife>, - { - match self.field { - #(#variant_arms)* - } - } - } - - struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result - where - __A: _serde::de::MapAccess<#delife>, - { - // Visit the first relevant key. - match #next_relevant_key { - // First key is the tag. - _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { - // Parse the tag. - let __field = try!(_serde::de::MapAccess::next_value(&mut __map)); - // Visit the second key. - match #next_relevant_key { - // Second key is a duplicate of the tag. - _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { - _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) - } - // Second key is the content. - _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { - let __ret = try!(_serde::de::MapAccess::next_value_seed(&mut __map, - __Seed { - field: __field, - marker: _serde::export::PhantomData, - lifetime: _serde::export::PhantomData, - })); - // Visit remaining keys, looking for duplicates. - #visit_remaining_keys - } - // There is no second key; might be okay if the we have a unit variant. - _serde::export::None => #missing_content - } - } - // First key is the content. - _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { - // Buffer up the content. - let __content = try!(_serde::de::MapAccess::next_value::<_serde::private::de::Content>(&mut __map)); - // Visit the second key. - match #next_relevant_key { - // Second key is the tag. - _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { - let __deserializer = _serde::private::de::ContentDeserializer::<__A::Error>::new(__content); - #finish_content_then_tag - } - // Second key is a duplicate of the content. - _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { - _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) - } - // There is no second key. - _serde::export::None => { - _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) - } - } - } - // There is no first key. - _serde::export::None => { - _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) - } - } - } - - fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - // Visit the first element - the tag. - match try!(_serde::de::SeqAccess::next_element(&mut __seq)) { - _serde::export::Some(__field) => { - // Visit the second element - the content. - match try!(_serde::de::SeqAccess::next_element_seed( - &mut __seq, - __Seed { - field: __field, - marker: _serde::export::PhantomData, - lifetime: _serde::export::PhantomData, - }, - )) { - _serde::export::Some(__ret) => _serde::export::Ok(__ret), - // There is no second element. - _serde::export::None => { - _serde::export::Err(_serde::de::Error::invalid_length(1, &self)) - } - } - } - // There is no first element. - _serde::export::None => { - _serde::export::Err(_serde::de::Error::invalid_length(0, &self)) - } - } - } - } - - const FIELDS: &'static [&'static str] = &[#tag, #content]; - _serde::Deserializer::deserialize_struct( - __deserializer, - #type_name, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::<#this #ty_generics>, - lifetime: _serde::export::PhantomData, - }, - ) - } -} - -fn deserialize_untagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - let attempts = variants - .iter() - .filter(|variant| !variant.attrs.skip_deserializing()) - .map(|variant| { - Expr(deserialize_untagged_variant( - params, - variant, - cattrs, - quote!(_serde::private::de::ContentRefDeserializer::<__D::Error>::new(&__content)), - )) - }); - - // TODO this message could be better by saving the errors from the failed - // attempts. The heuristic used by TOML was to count the number of fields - // processed before an error, and use the error that happened after the - // largest number of fields. I'm not sure I like that. Maybe it would be - // better to save all the errors and combine them into one message that - // explains why none of the variants matched. - let fallthrough_msg = format!( - "data did not match any variant of untagged enum {}", - params.type_name() - ); - - quote_block! { - let __content = try!(<_serde::private::de::Content as _serde::Deserialize>::deserialize(__deserializer)); - - #( - if let _serde::export::Ok(__ok) = #attempts { - return _serde::export::Ok(__ok); - } - )* - - _serde::export::Err(_serde::de::Error::custom(#fallthrough_msg)) - } -} - -fn deserialize_externally_tagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, -) -> Fragment { - if let Some(path) = variant.attrs.deserialize_with() { - let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); - return quote_block! { - #wrapper - _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) - }; - } - - let variant_ident = &variant.ident; - - match variant.style { - Style::Unit => { - let this = ¶ms.this; - quote_block! { - try!(_serde::de::VariantAccess::unit_variant(__variant)); - _serde::export::Ok(#this::#variant_ident) - } - } - Style::Newtype => deserialize_externally_tagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - cattrs, - ), - Style::Tuple => { - deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None) - } - Style::Struct => deserialize_struct( - Some(variant_ident), - params, - &variant.fields, - cattrs, - None, - &Untagged::No, - ), - } -} - -fn deserialize_internally_tagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, - deserializer: TokenStream, -) -> Fragment { - if variant.attrs.deserialize_with().is_some() { - return deserialize_untagged_variant(params, variant, cattrs, deserializer); - } - - let variant_ident = &variant.ident; - - match effective_style(variant) { - Style::Unit => { - let this = ¶ms.this; - let type_name = params.type_name(); - 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! { - try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))); - _serde::export::Ok(#this::#variant_ident #default) - } - } - Style::Newtype => deserialize_untagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - &deserializer, - ), - Style::Struct => deserialize_struct( - Some(variant_ident), - params, - &variant.fields, - cattrs, - Some(deserializer), - &Untagged::No, - ), - Style::Tuple => unreachable!("checked in serde_derive_internals"), - } -} - -fn deserialize_untagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, - deserializer: TokenStream, -) -> Fragment { - if let Some(path) = variant.attrs.deserialize_with() { - let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); - return quote_block! { - #wrapper - _serde::export::Result::map( - <#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn) - }; - } - - let variant_ident = &variant.ident; - - match effective_style(variant) { - Style::Unit => { - let this = ¶ms.this; - let type_name = params.type_name(); - 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! { - match _serde::Deserializer::deserialize_any( - #deserializer, - _serde::private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) - ) { - _serde::export::Ok(()) => _serde::export::Ok(#this::#variant_ident #default), - _serde::export::Err(__err) => _serde::export::Err(__err), - } - } - } - Style::Newtype => deserialize_untagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - &deserializer, - ), - Style::Tuple => deserialize_tuple( - Some(variant_ident), - params, - &variant.fields, - cattrs, - Some(deserializer), - ), - Style::Struct => deserialize_struct( - Some(variant_ident), - params, - &variant.fields, - cattrs, - Some(deserializer), - &Untagged::Yes, - ), - } -} - -fn deserialize_externally_tagged_newtype_variant( - variant_ident: &syn::Ident, - params: &Parameters, - field: &Field, - cattrs: &attr::Container, -) -> Fragment { - let this = ¶ms.this; - - if field.attrs.skip_deserializing() { - let this = ¶ms.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() { - None => { - let field_ty = field.ty; - let span = field.original.span(); - let func = - quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); - quote_expr! { - _serde::export::Result::map(#func(__variant), #this::#variant_ident) - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote_block! { - #wrapper - _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), - |__wrapper| #this::#variant_ident(__wrapper.value)) - } - } - } -} - -fn deserialize_untagged_newtype_variant( - variant_ident: &syn::Ident, - params: &Parameters, - field: &Field, - deserializer: &TokenStream, -) -> Fragment { - let this = ¶ms.this; - let field_ty = field.ty; - match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); - quote_expr! { - _serde::export::Result::map(#func(#deserializer), #this::#variant_ident) - } - } - Some(path) => { - quote_block! { - let __value: _serde::export::Result<#field_ty, _> = #path(#deserializer); - _serde::export::Result::map(__value, #this::#variant_ident) - } - } - } -} - -fn deserialize_generated_identifier( - fields: &[(String, Ident, Vec)], - cattrs: &attr::Container, - is_variant: bool, - other_idx: Option, -) -> Fragment { - let this = quote!(__Field); - let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect(); - - let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { - let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),); - let fallthrough = quote!(_serde::export::Ok(__Field::__other(__value))); - (Some(ignore_variant), Some(fallthrough)) - } else if let Some(other_idx) = other_idx { - let ignore_variant = fields[other_idx].1.clone(); - let fallthrough = quote!(_serde::export::Ok(__Field::#ignore_variant)); - (None, Some(fallthrough)) - } else if is_variant || cattrs.deny_unknown_fields() { - (None, None) - } else { - let ignore_variant = quote!(__ignore,); - let fallthrough = quote!(_serde::export::Ok(__Field::__ignore)); - (Some(ignore_variant), Some(fallthrough)) - }; - - let visitor_impl = Stmts(deserialize_identifier( - &this, - fields, - is_variant, - fallthrough, - !is_variant && cattrs.has_flatten(), - )); - - let lifetime = if !is_variant && cattrs.has_flatten() { - Some(quote!(<'de>)) - } else { - None - }; - - quote_block! { - #[allow(non_camel_case_types)] - enum __Field #lifetime { - #(#field_idents,)* - #ignore_variant - } - - struct __FieldVisitor; - - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field #lifetime; - - #visitor_impl - } - - impl<'de> _serde::Deserialize<'de> for __Field #lifetime { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - } -} - -fn deserialize_custom_identifier( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - let is_variant = match cattrs.identifier() { - attr::Identifier::Variant => true, - attr::Identifier::Field => false, - attr::Identifier::No => unreachable!(), - }; - - let this = ¶ms.this; - let this = quote!(#this); - - let (ordinary, fallthrough) = if let Some(last) = variants.last() { - let last_ident = &last.ident; - if last.attrs.other() { - let ordinary = &variants[..variants.len() - 1]; - let fallthrough = quote!(_serde::export::Ok(#this::#last_ident)); - (ordinary, Some(fallthrough)) - } else if let Style::Newtype = last.style { - let ordinary = &variants[..variants.len() - 1]; - let deserializer = quote!(_serde::private::de::IdentifierDeserializer::from(__value)); - let fallthrough = quote! { - _serde::export::Result::map( - _serde::Deserialize::deserialize(#deserializer), - #this::#last_ident) - }; - (ordinary, Some(fallthrough)) - } else { - (variants, None) - } - } else { - (variants, None) - }; - - let names_idents: Vec<_> = ordinary - .iter() - .map(|variant| { - ( - variant.attrs.name().deserialize_name(), - variant.ident.clone(), - variant.attrs.aliases(), - ) - }) - .collect(); - - let names = names_idents.iter().map(|(name, _, _)| name); - - let names_const = if fallthrough.is_some() { - None - } else if is_variant { - let variants = quote! { - const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(variants) - } else { - let fields = quote! { - const FIELDS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(fields) - }; - - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - let visitor_impl = Stmts(deserialize_identifier( - &this, - &names_idents, - is_variant, - fallthrough, - false, - )); - - quote_block! { - #names_const - - struct __FieldVisitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause { - type Value = #this #ty_generics; - - #visitor_impl - } - - let __visitor = __FieldVisitor { - marker: _serde::export::PhantomData::<#this #ty_generics>, - lifetime: _serde::export::PhantomData, - }; - _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) - } -} - -fn deserialize_identifier( - this: &TokenStream, - fields: &[(String, Ident, Vec)], - is_variant: bool, - fallthrough: Option, - collect_other_fields: bool, -) -> Fragment { - let mut flat_fields = Vec::new(); - for (_, ident, aliases) in fields { - flat_fields.extend(aliases.iter().map(|alias| (alias, ident))) - } - - let field_strs = flat_fields.iter().map(|(name, _)| name); - let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name); - let field_bytes = flat_fields - .iter() - .map(|(name, _)| Literal::byte_string(name.as_bytes())); - let field_borrowed_bytes = flat_fields - .iter() - .map(|(name, _)| Literal::byte_string(name.as_bytes())); - - let constructors: &Vec<_> = &flat_fields - .iter() - .map(|(_, ident)| quote!(#this::#ident)) - .collect(); - let main_constructors: &Vec<_> = &fields - .iter() - .map(|(_, ident, _)| quote!(#this::#ident)) - .collect(); - - let expecting = if is_variant { - "variant identifier" - } else { - "field identifier" - }; - - let index_expecting = if is_variant { "variant" } else { "field" }; - - let bytes_to_str = if fallthrough.is_some() || collect_other_fields { - None - } else { - Some(quote! { - let __value = &_serde::export::from_utf8_lossy(__value); - }) - }; - - let ( - value_as_str_content, - value_as_borrowed_str_content, - value_as_bytes_content, - value_as_borrowed_bytes_content, - ) = if collect_other_fields { - ( - Some(quote! { - let __value = _serde::private::de::Content::String(_serde::export::ToString::to_string(__value)); - }), - Some(quote! { - let __value = _serde::private::de::Content::Str(__value); - }), - Some(quote! { - let __value = _serde::private::de::Content::ByteBuf(__value.to_vec()); - }), - Some(quote! { - let __value = _serde::private::de::Content::Bytes(__value); - }), - ) - } else { - (None, None, None, None) - }; - - let fallthrough_arm = if let Some(fallthrough) = fallthrough { - fallthrough - } else if is_variant { - quote! { - _serde::export::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) - } - } else { - quote! { - _serde::export::Err(_serde::de::Error::unknown_field(__value, FIELDS)) - } - }; - - let variant_indices = 0_u64..; - let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); - let visit_other = if collect_other_fields { - quote! { - fn visit_bool<__E>(self, __value: bool) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::Bool(__value))) - } - - fn visit_i8<__E>(self, __value: i8) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::I8(__value))) - } - - fn visit_i16<__E>(self, __value: i16) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::I16(__value))) - } - - fn visit_i32<__E>(self, __value: i32) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::I32(__value))) - } - - fn visit_i64<__E>(self, __value: i64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::I64(__value))) - } - - fn visit_u8<__E>(self, __value: u8) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::U8(__value))) - } - - fn visit_u16<__E>(self, __value: u16) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::U16(__value))) - } - - fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::U32(__value))) - } - - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::U64(__value))) - } - - fn visit_f32<__E>(self, __value: f32) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::F32(__value))) - } - - fn visit_f64<__E>(self, __value: f64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::F64(__value))) - } - - fn visit_char<__E>(self, __value: char) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::Char(__value))) - } - - fn visit_unit<__E>(self) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(__Field::__other(_serde::private::de::Content::Unit)) - } - - fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_borrowed_strs => _serde::export::Ok(#constructors), - )* - _ => { - #value_as_borrowed_str_content - #fallthrough_arm - } - } - } - - fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_borrowed_bytes => _serde::export::Ok(#constructors), - )* - _ => { - #bytes_to_str - #value_as_borrowed_bytes_content - #fallthrough_arm - } - } - } - } - } else { - quote! { - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #variant_indices => _serde::export::Ok(#main_constructors), - )* - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &#fallthrough_msg, - )) - } - } - } - }; - - quote_block! { - fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, #expecting) - } - - #visit_other - - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_strs => _serde::export::Ok(#constructors), - )* - _ => { - #value_as_str_content - #fallthrough_arm - } - } - } - - fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_bytes => _serde::export::Ok(#constructors), - )* - _ => { - #bytes_to_str - #value_as_bytes_content - #fallthrough_arm - } - } - } - } -} - -fn deserialize_struct_as_struct_visitor( - struct_path: &TokenStream, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> (Fragment, Option, Fragment) { - assert!(!cattrs.has_flatten()); - - let field_names_idents: Vec<_> = fields - .iter() - .enumerate() - .filter(|&(_, field)| !field.attrs.skip_deserializing()) - .map(|(i, field)| { - ( - field.attrs.name().deserialize_name(), - field_i(i), - field.attrs.aliases(), - ) - }) - .collect(); - - let fields_stmt = { - let field_names = field_names_idents.iter().map(|(name, _, _)| name); - quote_block! { - const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; - } - }; - - let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); - - let visit_map = deserialize_map(struct_path, params, fields, cattrs); - - (field_visitor, Some(fields_stmt), visit_map) -} - -fn deserialize_struct_as_map_visitor( - struct_path: &TokenStream, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> (Fragment, Option, Fragment) { - let field_names_idents: Vec<_> = fields - .iter() - .enumerate() - .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(i, field)| { - ( - field.attrs.name().deserialize_name(), - field_i(i), - field.attrs.aliases(), - ) - }) - .collect(); - - let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); - - let visit_map = deserialize_map(struct_path, params, fields, cattrs); - - (field_visitor, None, visit_map) -} - -fn deserialize_map( - struct_path: &TokenStream, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> Fragment { - // Create the field names for the fields. - let fields_names: Vec<_> = fields - .iter() - .enumerate() - .map(|(i, field)| (field, field_i(i))) - .collect(); - - // Declare each field that will be deserialized. - let let_values = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let field_ty = field.ty; - quote! { - let mut #name: _serde::export::Option<#field_ty> = _serde::export::None; - } - }); - - // Collect contents for flatten fields into a buffer - let let_collect = if cattrs.has_flatten() { - Some(quote! { - let mut __collect = _serde::export::Vec::<_serde::export::Option<( - _serde::private::de::Content, - _serde::private::de::Content - )>>::new(); - }) - } else { - None - }; - - // Match arms to extract a value for a field. - let value_arms = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let deser_name = field.attrs.name().deserialize_name(); - - let visit = match field.attrs.deserialize_with() { - None => { - let field_ty = field.ty; - let span = field.original.span(); - let func = - quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); - quote! { - try!(#func(&mut __map)) - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote!({ - #wrapper - match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { - _serde::export::Ok(__wrapper) => __wrapper.value, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - }) - } - }; - quote! { - __Field::#name => { - if _serde::export::Option::is_some(&#name) { - return _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); - } - #name = _serde::export::Some(#visit); - } - } - }); - - // Visit ignored values to consume them - let ignored_arm = if cattrs.has_flatten() { - Some(quote! { - __Field::__other(__name) => { - __collect.push(_serde::export::Some(( - __name, - try!(_serde::de::MapAccess::next_value(&mut __map))))); - } - }) - } else if cattrs.deny_unknown_fields() { - None - } else { - Some(quote! { - _ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); } - }) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let match_keys = if cattrs.deny_unknown_fields() && all_skipped { - quote! { - // FIXME: Once we drop support for Rust 1.15: - // let _serde::export::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); - _serde::export::Option::map( - try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), - |__impossible| match __impossible {}); - } - } else { - quote! { - while let _serde::export::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) { - match __key { - #(#value_arms)* - #ignored_arm - } - } - } - }; - - let extract_values = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let missing_expr = Match(expr_is_missing(field, cattrs)); - - quote! { - let #name = match #name { - _serde::export::Some(#name) => #name, - _serde::export::None => #missing_expr - }; - } - }); - - let extract_collected = fields_names - .iter() - .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let field_ty = field.ty; - let func = match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - quote_spanned!(span=> _serde::de::Deserialize::deserialize) - } - Some(path) => quote!(#path), - }; - quote! { - let #name: #field_ty = try!(#func( - _serde::private::de::FlatMapDeserializer( - &mut __collect, - _serde::export::PhantomData))); - } - }); - - let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { - Some(quote! { - if let _serde::export::Some(_serde::export::Some((__key, _))) = - __collect.into_iter().filter(_serde::export::Option::is_some).next() - { - if let _serde::export::Some(__key) = __key.as_str() { - return _serde::export::Err( - _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); - } else { - return _serde::export::Err( - _serde::de::Error::custom(format_args!("unexpected map key"))); - } - } - }) - } else { - None - }; - - let result = fields_names.iter().map(|(field, name)| { - let member = &field.member; - if field.attrs.skip_deserializing() { - let value = Expr(expr_is_missing(field, cattrs)); - quote!(#member: #value) - } else { - quote!(#member: #name) - } - }); - - let let_default = match cattrs.default() { - attr::Default::Default => Some(quote!( - let __default: Self::Value = _serde::export::Default::default(); - )), - attr::Default::Path(path) => Some(quote!( - let __default: Self::Value = #path(); - )), - attr::Default::None => { - // We don't need the default value, to prevent an unused variable warning - // we'll leave the line empty. - None - } - }; - - let mut result = quote!(#struct_path { #(#result),* }); - if params.has_getter { - let this = ¶ms.this; - result = quote! { - _serde::export::Into::<#this>::into(#result) - }; - } - - quote_block! { - #(#let_values)* - - #let_collect - - #match_keys - - #let_default - - #(#extract_values)* - - #(#extract_collected)* - - #collected_deny_unknown_fields - - _serde::export::Ok(#result) - } -} - -#[cfg(feature = "deserialize_in_place")] -fn deserialize_struct_as_struct_in_place_visitor( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> (Fragment, Fragment, Fragment) { - assert!(!cattrs.has_flatten()); - - let field_names_idents: Vec<_> = fields - .iter() - .enumerate() - .filter(|&(_, field)| !field.attrs.skip_deserializing()) - .map(|(i, field)| { - ( - field.attrs.name().deserialize_name(), - field_i(i), - field.attrs.aliases(), - ) - }) - .collect(); - - let fields_stmt = { - let field_names = field_names_idents.iter().map(|(name, _, _)| name); - quote_block! { - const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; - } - }; - - let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); - - let visit_map = deserialize_map_in_place(params, fields, cattrs); - - (field_visitor, fields_stmt, visit_map) -} - -#[cfg(feature = "deserialize_in_place")] -fn deserialize_map_in_place( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> Fragment { - assert!(!cattrs.has_flatten()); - - // Create the field names for the fields. - let fields_names: Vec<_> = fields - .iter() - .enumerate() - .map(|(i, field)| (field, field_i(i))) - .collect(); - - // For deserialize_in_place, declare booleans for each field that will be - // deserialized. - let let_flags = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(_, name)| { - quote! { - let mut #name: bool = false; - } - }); - - // Match arms to extract a value for a field. - let value_arms_from = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let deser_name = field.attrs.name().deserialize_name(); - let member = &field.member; - - let visit = match field.attrs.deserialize_with() { - None => { - quote! { - try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#member))) - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote!({ - #wrapper - self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { - _serde::export::Ok(__wrapper) => __wrapper.value, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }) - } - }; - quote! { - __Field::#name => { - if #name { - return _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); - } - #visit; - #name = true; - } - } - }); - - // Visit ignored values to consume them - let ignored_arm = if cattrs.deny_unknown_fields() { - None - } else { - Some(quote! { - _ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); } - }) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - - let match_keys = if cattrs.deny_unknown_fields() && all_skipped { - quote! { - // FIXME: Once we drop support for Rust 1.15: - // let _serde::export::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); - _serde::export::Option::map( - try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), - |__impossible| match __impossible {}); - } - } else { - quote! { - while let _serde::export::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) { - match __key { - #(#value_arms_from)* - #ignored_arm - } - } - } - }; - - let check_flags = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let missing_expr = expr_is_missing(field, cattrs); - // If missing_expr unconditionally returns an error, don't try - // to assign its value to self.place. - if field.attrs.default().is_none() - && cattrs.default().is_none() - && field.attrs.deserialize_with().is_some() - { - let missing_expr = Stmts(missing_expr); - quote! { - if !#name { - #missing_expr; - } - } - } else { - let member = &field.member; - let missing_expr = Expr(missing_expr); - quote! { - if !#name { - self.place.#member = #missing_expr; - }; - } - } - }); - - let this = ¶ms.this; - let (_, _, ty_generics, _) = split_with_de_lifetime(params); - - let let_default = match cattrs.default() { - attr::Default::Default => Some(quote!( - let __default: #this #ty_generics = _serde::export::Default::default(); - )), - attr::Default::Path(path) => Some(quote!( - let __default: #this #ty_generics = #path(); - )), - attr::Default::None => { - // We don't need the default value, to prevent an unused variable warning - // we'll leave the line empty. - None - } - }; - - quote_block! { - #(#let_flags)* - - #match_keys - - #let_default - - #(#check_flags)* - - _serde::export::Ok(()) - } -} - -fn field_i(i: usize) -> Ident { - Ident::new(&format!("__field{}", i), Span::call_site()) -} - -/// This function wraps the expression in `#[serde(deserialize_with = "...")]` -/// in a trait to prevent it from accessing the internal `Deserialize` state. -fn wrap_deserialize_with( - params: &Parameters, - value_ty: &TokenStream, - deserialize_with: &syn::ExprPath, -) -> (TokenStream, TokenStream) { - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); - let delife = params.borrowed.de_lifetime(); - - let wrapper = quote! { - struct __DeserializeWith #de_impl_generics #where_clause { - value: #value_ty, - phantom: _serde::export::PhantomData<#this #ty_generics>, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<#delife>, - { - _serde::export::Ok(__DeserializeWith { - value: try!(#deserialize_with(__deserializer)), - phantom: _serde::export::PhantomData, - lifetime: _serde::export::PhantomData, - }) - } - } - }; - - let wrapper_ty = quote!(__DeserializeWith #de_ty_generics); - - (wrapper, wrapper_ty) -} - -fn wrap_deserialize_field_with( - params: &Parameters, - field_ty: &syn::Type, - deserialize_with: &syn::ExprPath, -) -> (TokenStream, TokenStream) { - wrap_deserialize_with(params, "e!(#field_ty), deserialize_with) -} - -fn wrap_deserialize_variant_with( - params: &Parameters, - variant: &Variant, - deserialize_with: &syn::ExprPath, -) -> (TokenStream, TokenStream, TokenStream) { - let this = ¶ms.this; - let variant_ident = &variant.ident; - - let field_tys = variant.fields.iter().map(|field| field.ty); - let (wrapper, wrapper_ty) = - wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); - - let field_access = (0..variant.fields.len()).map(|n| { - Member::Unnamed(Index { - index: n as u32, - span: Span::call_site(), - }) - }); - let unwrap_fn = match variant.style { - Style::Struct if variant.fields.len() == 1 => { - let member = &variant.fields[0].member; - quote! { - |__wrap| #this::#variant_ident { #member: __wrap.value } - } - } - Style::Struct => { - let members = variant.fields.iter().map(|field| &field.member); - quote! { - |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* } - } + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote! { + |#arg| #this_value::#variant_ident { #(#members: #wrapper.#field_access),* } + } } Style::Tuple => quote! { - |__wrap| #this::#variant_ident(#(__wrap.value.#field_access),*) + |#arg| #this_value::#variant_ident(#(#wrapper.#field_access),*) }, Style::Newtype => quote! { - |__wrap| #this::#variant_ident(__wrap.value) + |#arg| #this_value::#variant_ident(#wrapper) }, Style::Unit => quote! { - |__wrap| #this::#variant_ident + |#arg| #this_value::#variant_ident }, - }; - - (wrapper, wrapper_ty, unwrap_fn) + } } fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { match field.attrs.default() { attr::Default::Default => { let span = field.original.span(); - let func = quote_spanned!(span=> _serde::export::Default::default); + let func = quote_spanned!(span=> _serde::#private::Default::default); return quote_expr!(#func()); } attr::Default::Path(path) => { - return quote_expr!(#path()); + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + return Fragment::Expr(quote_spanned!(path.span()=> #path())); } attr::Default::None => { /* below */ } } @@ -2888,19 +792,52 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { match field.attrs.deserialize_with() { None => { let span = field.original.span(); - let func = quote_spanned!(span=> _serde::private::de::missing_field); + let func = quote_spanned!(span=> _serde::#private::de::missing_field); quote_expr! { - try!(#func(#name)) + #func(#name)? } } Some(_) => { quote_expr! { - return _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#name)) + return _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#name)) } } } } +fn expr_is_missing_seq( + assign_to: Option, + index: usize, + field: &Field, + cattrs: &attr::Container, + expecting: &str, +) -> TokenStream { + match field.attrs.default() { + attr::Default::Default => { + let span = field.original.span(); + return quote_spanned!(span=> #assign_to _serde::#private::Default::default()); + } + attr::Default::Path(path) => { + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + return quote_spanned!(path.span()=> #assign_to #path()); + } + attr::Default::None => { /* below */ } + } + + match *cattrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let member = &field.member; + quote!(#assign_to __default.#member) + } + attr::Default::None => quote!( + return _serde::#private::Err(_serde::de::Error::invalid_length(#index, &#expecting)) + ), + } +} + fn effective_style(variant: &Variant) -> Style { match variant.style { Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit, @@ -2908,6 +845,14 @@ fn effective_style(variant: &Variant) -> Style { } } +/// True if there is any field with a `#[serde(flatten)]` attribute, other than +/// fields which are skipped. +fn has_flatten(fields: &[Field]) -> bool { + fields + .iter() + .any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing()) +} + struct DeImplGenerics<'a>(&'a Parameters); #[cfg(feature = "deserialize_in_place")] struct InPlaceImplGenerics<'a>(&'a Parameters); @@ -2915,7 +860,7 @@ struct InPlaceImplGenerics<'a>(&'a Parameters); impl<'a> ToTokens for DeImplGenerics<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let mut generics = self.0.generics.clone(); - if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) .into_iter() .chain(generics.params) @@ -2950,7 +895,7 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> { .into_iter() .chain(generics.params) .collect(); - if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) .into_iter() .chain(generics.params) @@ -2972,23 +917,31 @@ struct DeTypeGenerics<'a>(&'a Parameters); #[cfg(feature = "deserialize_in_place")] struct InPlaceTypeGenerics<'a>(&'a Parameters); +fn de_type_generics_to_tokens( + mut generics: syn::Generics, + borrowed: &BorrowedLifetimes, + tokens: &mut TokenStream, +) { + if borrowed.de_lifetime_param().is_some() { + let def = syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + }; + // Prepend 'de lifetime to list of generics + generics.params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (_, ty_generics, _) = generics.split_for_impl(); + ty_generics.to_tokens(tokens); +} + impl<'a> ToTokens for DeTypeGenerics<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { - let mut generics = self.0.generics.clone(); - if self.0.borrowed.de_lifetime_def().is_some() { - let def = syn::LifetimeDef { - attrs: Vec::new(), - lifetime: syn::Lifetime::new("'de", Span::call_site()), - colon_token: None, - bounds: Punctuated::new(), - }; - generics.params = Some(syn::GenericParam::Lifetime(def)) - .into_iter() - .chain(generics.params) - .collect(); - } - let (_, ty_generics, _) = generics.split_for_impl(); - ty_generics.to_tokens(tokens); + de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens); } } @@ -3001,20 +954,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> { .chain(generics.params) .collect(); - if self.0.borrowed.de_lifetime_def().is_some() { - let def = syn::LifetimeDef { - attrs: Vec::new(), - lifetime: syn::Lifetime::new("'de", Span::call_site()), - colon_token: None, - bounds: Punctuated::new(), - }; - generics.params = Some(syn::GenericParam::Lifetime(def)) - .into_iter() - .chain(generics.params) - .collect(); - } - let (_, ty_generics, _) = generics.split_for_impl(); - ty_generics.to_tokens(tokens); + de_type_generics_to_tokens(generics, &self.0.borrowed, tokens); } } @@ -3026,25 +966,11 @@ impl<'a> DeTypeGenerics<'a> { } #[cfg(feature = "deserialize_in_place")] -fn place_lifetime() -> syn::LifetimeDef { - syn::LifetimeDef { +fn place_lifetime() -> syn::LifetimeParam { + syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'place", Span::call_site()), colon_token: None, bounds: Punctuated::new(), } } - -fn split_with_de_lifetime( - params: &Parameters, -) -> ( - DeImplGenerics, - DeTypeGenerics, - syn::TypeGenerics, - Option<&syn::WhereClause>, -) { - let de_impl_generics = DeImplGenerics(params); - let de_ty_generics = DeTypeGenerics(params); - let (_, ty_generics, where_clause) = params.generics.split_for_impl(); - (de_impl_generics, de_ty_generics, ty_generics, where_clause) -} diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs new file mode 100644 index 000000000..6f5094ff4 --- /dev/null +++ b/serde_derive/src/de/enum_.rs @@ -0,0 +1,96 @@ +use crate::de::enum_adjacently; +use crate::de::enum_externally; +use crate::de::enum_internally; +use crate::de::enum_untagged; +use crate::de::identifier; +use crate::de::{field_i, FieldWithAliases, Parameters}; +use crate::fragment::{Expr, Fragment, Stmts}; +use crate::internals::ast::Variant; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` +pub(super) fn deserialize( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + // The variants have already been checked (in ast.rs) that all untagged variants appear at the end + match variants.iter().position(|var| var.attrs.untagged()) { + Some(variant_idx) => { + let (tagged, untagged) = variants.split_at(variant_idx); + let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); + // Ignore any error associated with non-untagged deserialization so that we + // can fall through to the untagged variants. This may be infallible so we + // need to provide the error type. + let first_attempt = quote! { + if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() { + return _serde::#private::Ok(__ok); + } + }; + enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt)) + } + None => deserialize_homogeneous_enum(params, variants, cattrs), + } +} + +fn deserialize_homogeneous_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + match cattrs.tag() { + attr::TagType::External => enum_externally::deserialize(params, variants, cattrs), + attr::TagType::Internal { tag } => { + enum_internally::deserialize(params, variants, cattrs, tag) + } + attr::TagType::Adjacent { tag, content } => { + enum_adjacently::deserialize(params, variants, cattrs, tag, content) + } + attr::TagType::None => enum_untagged::deserialize(params, variants, cattrs, None), + } +} + +pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { + let deserialized_variants = variants + .iter() + .enumerate() + .filter(|&(_i, variant)| !variant.attrs.skip_deserializing()); + + let fallthrough = deserialized_variants + .clone() + .find(|(_i, variant)| variant.attrs.other()) + .map(|(i, _variant)| { + let ignore_variant = field_i(i); + quote!(_serde::#private::Ok(__Field::#ignore_variant)) + }); + + let variants_stmt = { + let variant_names = deserialized_variants + .clone() + .flat_map(|(_i, variant)| variant.attrs.aliases()); + quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; + } + }; + + let deserialized_variants: Vec<_> = deserialized_variants + .map(|(i, variant)| FieldWithAliases { + ident: field_i(i), + aliases: variant.attrs.aliases(), + }) + .collect(); + + let variant_visitor = Stmts(identifier::deserialize_generated( + &deserialized_variants, + false, // variant identifiers do not depend on the presence of flatten fields + true, + None, + fallthrough, + )); + + (variants_stmt, variant_visitor) +} diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs new file mode 100644 index 000000000..cbb90dbd1 --- /dev/null +++ b/serde_derive/src/de/enum_adjacently.rs @@ -0,0 +1,325 @@ +//! Deserialization for adjacently tagged enums: +//! +//! ```ignore +//! #[serde(tag = "...", content = "...")] +//! enum Enum {} +//! ``` + +use crate::de::enum_; +use crate::de::enum_untagged; +use crate::de::{field_i, Parameters}; +use crate::fragment::{Fragment, Match}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes +pub(super) fn deserialize( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, + content: &str, +) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); + + let variant_arms: &Vec<_> = &variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_index = field_i(i); + + let block = Match(enum_untagged::deserialize_variant(params, variant, cattrs)); + + quote! { + __Field::#variant_index => #block + } + }) + .collect(); + + let rust_name = params.type_name(); + let expecting = format!("adjacently tagged enum {}", rust_name); + let expecting = cattrs.expecting().unwrap_or(&expecting); + let type_name = cattrs.name().deserialize_name(); + let deny_unknown_fields = cattrs.deny_unknown_fields(); + + // If unknown fields are allowed, we pick the visitor that can step over + // those. Otherwise we pick the visitor that fails on unknown keys. + let field_visitor_ty = if deny_unknown_fields { + quote! { _serde::#private::de::TagOrContentFieldVisitor } + } else { + quote! { _serde::#private::de::TagContentOtherFieldVisitor } + }; + + let mut missing_content = quote! { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) + }; + let mut missing_content_fallthrough = quote!(); + let missing_content_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .filter_map(|(i, variant)| { + let variant_index = field_i(i); + let variant_ident = &variant.ident; + + let arm = match variant.style { + Style::Unit => quote! { + _serde::#private::Ok(#this_value::#variant_ident) + }, + Style::Newtype if variant.attrs.deserialize_with().is_none() => { + let span = variant.original.span(); + let func = quote_spanned!(span=> _serde::#private::de::missing_field); + quote! { + #func(#content).map(#this_value::#variant_ident) + } + } + _ => { + missing_content_fallthrough = quote!(_ => #missing_content); + return None; + } + }; + Some(quote! { + __Field::#variant_index => #arm, + }) + }) + .collect::>(); + if !missing_content_arms.is_empty() { + missing_content = quote! { + match __field { + #(#missing_content_arms)* + #missing_content_fallthrough + } + }; + } + + // Advance the map by one key, returning early in case of error. + let next_key = quote! { + _serde::de::MapAccess::next_key_seed(&mut __map, #field_visitor_ty { + tag: #tag, + content: #content, + })? + }; + + let variant_from_map = quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> { + enum_name: #rust_name, + variants: VARIANTS, + fields_enum: _serde::#private::PhantomData + })? + }; + + // When allowing unknown fields, we want to transparently step through keys + // we don't care about until we find `tag`, `content`, or run out of keys. + let next_relevant_key = if deny_unknown_fields { + next_key + } else { + quote!({ + let mut __rk : _serde::#private::Option<_serde::#private::de::TagOrContentField> = _serde::#private::None; + while let _serde::#private::Some(__k) = #next_key { + match __k { + _serde::#private::de::TagContentOtherField::Other => { + let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; + continue; + }, + _serde::#private::de::TagContentOtherField::Tag => { + __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag); + break; + } + _serde::#private::de::TagContentOtherField::Content => { + __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Content); + break; + } + } + } + + __rk + }) + }; + + // Step through remaining keys, looking for duplicates of previously-seen + // keys. When unknown fields are denied, any key that isn't a duplicate will + // at this point immediately produce an error. + let visit_remaining_keys = quote! { + match #next_relevant_key { + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + _serde::#private::None => _serde::#private::Ok(__ret), + } + }; + + let finish_content_then_tag = if variant_arms.is_empty() { + quote! { + match #variant_from_map {} + } + } else { + quote! { + let __seed = __Seed { + variant: #variant_from_map, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + }; + let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content); + let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + }; + + quote_block! { + #variant_visitor + + #variants_stmt + + #[doc(hidden)] + struct __Seed #de_impl_generics #where_clause { + variant: __Field, + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<#delife>, + { + match self.variant { + #(#variant_arms)* + } + } + } + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + // Visit the first relevant key. + match #next_relevant_key { + // First key is the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + // Parse the tag. + let __field = #variant_from_map; + // Visit the second key. + match #next_relevant_key { + // Second key is a duplicate of the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + // Second key is the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + let __ret = _serde::de::MapAccess::next_value_seed(&mut __map, + __Seed { + variant: __field, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + })?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + // There is no second key; might be okay if the we have a unit variant. + _serde::#private::None => #missing_content + } + } + // First key is the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + // Buffer up the content. + let __content = _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?; + // Visit the second key. + match #next_relevant_key { + // Second key is the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + #finish_content_then_tag + } + // Second key is a duplicate of the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + // There is no second key. + _serde::#private::None => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + // There is no first key. + _serde::#private::None => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + + fn visit_seq<__A>(self, mut __seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + // Visit the first element - the tag. + match _serde::de::SeqAccess::next_element(&mut __seq) { + _serde::#private::Ok(_serde::#private::Some(__variant)) => { + // Visit the second element - the content. + match _serde::de::SeqAccess::next_element_seed( + &mut __seq, + __Seed { + variant: __variant, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + }, + ) { + _serde::#private::Ok(_serde::#private::Some(__ret)) => _serde::#private::Ok(__ret), + // There is no second element. + _serde::#private::Ok(_serde::#private::None) => { + _serde::#private::Err(_serde::de::Error::invalid_length(1, &self)) + } + _serde::#private::Err(__err) => _serde::#private::Err(__err), + } + } + // There is no first element. + _serde::#private::Ok(_serde::#private::None) => { + _serde::#private::Err(_serde::de::Error::invalid_length(0, &self)) + } + _serde::#private::Err(__err) => _serde::#private::Err(__err), + } + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[#tag, #content]; + _serde::Deserializer::deserialize_struct( + __deserializer, + #type_name, + FIELDS, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs new file mode 100644 index 000000000..1a4c36b4f --- /dev/null +++ b/serde_derive/src/de/enum_externally.rs @@ -0,0 +1,213 @@ +//! Deserialization for externally tagged enums: +//! +//! ```ignore +//! enum Enum {} +//! ``` + +use crate::de::enum_; +use crate::de::struct_; +use crate::de::tuple; +use crate::de::{ + expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, + wrap_deserialize_with, Parameters, StructForm, TupleForm, +}; +use crate::fragment::{Expr, Fragment, Match}; +use crate::internals::ast::{Field, Style, Variant}; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes +pub(super) fn deserialize( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + let type_name = cattrs.name().deserialize_name(); + let expecting = format!("enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_externally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + _serde::#private::Ok((__Field::#variant_name, __variant)) => #block + } + }); + + let all_skipped = variants + .iter() + .all(|variant| variant.attrs.skip_deserializing()); + let match_variant = if all_skipped { + // This is an empty enum like `enum Impossible {}` or an enum in which + // all variants have `#[serde(skip_deserializing)]`. + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); + // _serde::#private::Err(__err) + _serde::#private::Result::map( + _serde::de::EnumAccess::variant::<__Field>(__data), + |(__impossible, _)| match __impossible {}) + } + } else { + quote! { + match _serde::de::EnumAccess::variant(__data) { + #(#variant_arms)* + _serde::#private::Err(__err) => _serde::#private::Err(__err), + } + } + }; + + quote_block! { + #variant_visitor + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result + where + __A: _serde::de::EnumAccess<#delife>, + { + #match_variant + } + } + + #variants_stmt + + _serde::Deserializer::deserialize_enum( + __deserializer, + #type_name, + VARIANTS, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} + +fn deserialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); + return quote_block! { + #wrapper + _serde::#private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this_value = ¶ms.this_value; + quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::#private::Ok(#this_value::#variant_ident) + } + } + Style::Newtype => deserialize_externally_tagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + cattrs, + ), + Style::Tuple => tuple::deserialize( + params, + &variant.fields, + cattrs, + TupleForm::ExternallyTagged(variant_ident), + ), + Style::Struct => struct_::deserialize( + params, + &variant.fields, + cattrs, + StructForm::ExternallyTagged(variant_ident), + ), + } +} + +fn wrap_deserialize_variant_with( + params: &Parameters, + variant: &Variant, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream, TokenStream) { + let field_tys = variant.fields.iter().map(|field| field.ty); + let (wrapper, wrapper_ty) = + wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); + + let unwrap_fn = unwrap_to_variant_closure(params, variant, true); + + (wrapper, wrapper_ty, unwrap_fn) +} + +fn deserialize_externally_tagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let this_value = ¶ms.this_value; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + return quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::#private::Ok(#this_value::#variant_ident(#default)) + }; + } + + match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); + quote_expr! { + _serde::#private::Result::map(#func(__variant), #this_value::#variant_ident) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote_block! { + #wrapper + _serde::#private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), + |__wrapper| #this_value::#variant_ident(__wrapper.value)) + } + } + } +} diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs new file mode 100644 index 000000000..b669eef7e --- /dev/null +++ b/serde_derive/src/de/enum_internally.rs @@ -0,0 +1,106 @@ +//! Deserialization for internally tagged enums: +//! +//! ```ignore +//! #[serde(tag = "...")] +//! enum Enum {} +//! ``` + +use crate::de::enum_; +use crate::de::enum_untagged; +use crate::de::struct_; +use crate::de::{ + effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm, +}; +use crate::fragment::{Expr, Fragment, Match}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute +pub(super) fn deserialize( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_internally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + __Field::#variant_name => #block + } + }); + + let expecting = format!("internally tagged enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #variant_visitor + + #variants_stmt + + let (__tag, __content) = _serde::Deserializer::deserialize_any( + __deserializer, + _serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?; + let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content); + + match __tag { + #(#variant_arms)* + } + } +} + +// Generates significant part of the visit_seq and visit_map bodies of visitors +// for the variants of internally tagged enum. +fn deserialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_block! { + _serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; + _serde::#private::Ok(#this_value::#variant_ident #default) + } + } + Style::Newtype => { + enum_untagged::deserialize_newtype_variant(variant_ident, params, &variant.fields[0]) + } + Style::Struct => struct_::deserialize( + params, + &variant.fields, + cattrs, + StructForm::InternallyTagged(variant_ident), + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs new file mode 100644 index 000000000..f66d98de1 --- /dev/null +++ b/serde_derive/src/de/enum_untagged.rs @@ -0,0 +1,135 @@ +//! Deserialization for untagged enums: +//! +//! ```ignore +//! #[serde(untagged)] +//! enum Enum {} +//! ``` + +use crate::de::struct_; +use crate::de::tuple; +use crate::de::{ + effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm, +}; +use crate::fragment::{Expr, Fragment}; +use crate::internals::ast::{Field, Style, Variant}; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute +pub(super) fn deserialize( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + first_attempt: Option, +) -> Fragment { + let attempts = variants + .iter() + .filter(|variant| !variant.attrs.skip_deserializing()) + .map(|variant| Expr(deserialize_variant(params, variant, cattrs))); + // TODO this message could be better by saving the errors from the failed + // attempts. The heuristic used by TOML was to count the number of fields + // processed before an error, and use the error that happened after the + // largest number of fields. I'm not sure I like that. Maybe it would be + // better to save all the errors and combine them into one message that + // explains why none of the variants matched. + let fallthrough_msg = format!( + "data did not match any variant of untagged enum {}", + params.type_name() + ); + let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); + + let private2 = private; + quote_block! { + let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?; + let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content); + + #first_attempt + + #( + if let _serde::#private2::Ok(__ok) = #attempts { + return _serde::#private2::Ok(__ok); + } + )* + + _serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg)) + } +} + +// Also used by adjacently tagged enums +pub(super) fn deserialize_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_expr! { + match _serde::Deserializer::deserialize_any( + __deserializer, + _serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) + ) { + _serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default), + _serde::#private::Err(__err) => _serde::#private::Err(__err), + } + } + } + Style::Newtype => deserialize_newtype_variant(variant_ident, params, &variant.fields[0]), + Style::Tuple => tuple::deserialize( + params, + &variant.fields, + cattrs, + TupleForm::Untagged(variant_ident), + ), + Style::Struct => struct_::deserialize( + params, + &variant.fields, + cattrs, + StructForm::Untagged(variant_ident), + ), + } +} + +// Also used by internally tagged enums +// Implicitly (via `generate_variant`) used by adjacently tagged enums +pub(super) fn deserialize_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, +) -> Fragment { + let this_value = ¶ms.this_value; + let field_ty = field.ty; + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote_expr! { + _serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident) + } + } + Some(path) => { + quote_block! { + let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer); + _serde::#private::Result::map(__value, #this_value::#variant_ident) + } + } + } +} diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs new file mode 100644 index 000000000..8e67b9631 --- /dev/null +++ b/serde_derive/src/de/identifier.rs @@ -0,0 +1,477 @@ +//! Deserialization of struct field identifiers and enum variant identifiers by +//! way of a Rust enum. + +use crate::de::{FieldWithAliases, Parameters}; +use crate::fragment::{Fragment, Stmts}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use proc_macro2::{Literal, TokenStream}; +use quote::{quote, ToTokens}; + +// Generates `Deserialize::deserialize` body for an enum with +// `serde(field_identifier)` or `serde(variant_identifier)` attribute. +pub(super) fn deserialize_custom( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let is_variant = match cattrs.identifier() { + attr::Identifier::Variant => true, + attr::Identifier::Field => false, + attr::Identifier::No => unreachable!(), + }; + + let this_type = params.this_type.to_token_stream(); + let this_value = params.this_value.to_token_stream(); + + let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { + let last_ident = &last.ident; + if last.attrs.other() { + // Process `serde(other)` attribute. It would always be found on the + // last variant (checked in `check_identifier`), so all preceding + // are ordinary variants. + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident)); + (ordinary, Some(fallthrough), None) + } else if let Style::Newtype = last.style { + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = |value| { + quote! { + _serde::#private::Result::map( + _serde::Deserialize::deserialize( + _serde::#private::de::IdentifierDeserializer::from(#value) + ), + #this_value::#last_ident) + } + }; + ( + ordinary, + Some(fallthrough(quote!(__value))), + Some(fallthrough(quote!(_serde::#private::de::Borrowed( + __value + )))), + ) + } else { + (variants, None, None) + } + } else { + (variants, None, None) + }; + + let idents_aliases: Vec<_> = ordinary + .iter() + .map(|variant| FieldWithAliases { + ident: variant.ident.clone(), + aliases: variant.attrs.aliases(), + }) + .collect(); + + let names = idents_aliases.iter().flat_map(|variant| variant.aliases); + + let names_const = if fallthrough.is_some() { + None + } else if is_variant { + let variants = quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(variants) + } else { + let fields = quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(fields) + }; + + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + &idents_aliases, + is_variant, + fallthrough, + fallthrough_borrowed, + false, + cattrs.expecting(), + )); + + quote_block! { + #names_const + + #[doc(hidden)] + struct __FieldVisitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + #visitor_impl + } + + let __visitor = __FieldVisitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }; + _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) + } +} + +pub(super) fn deserialize_generated( + deserialized_fields: &[FieldWithAliases], + has_flatten: bool, + is_variant: bool, + ignore_variant: Option, + fallthrough: Option, +) -> Fragment { + let this_value = quote!(__Field); + let field_idents: &Vec<_> = &deserialized_fields + .iter() + .map(|field| &field.ident) + .collect(); + + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + deserialized_fields, + is_variant, + fallthrough, + None, + !is_variant && has_flatten, + None, + )); + + let lifetime = if !is_variant && has_flatten { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + #[doc(hidden)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + #[doc(hidden)] + struct __FieldVisitor; + + #[automatically_derived] + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + #[automatically_derived] + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + +fn deserialize_identifier( + this_value: &TokenStream, + deserialized_fields: &[FieldWithAliases], + is_variant: bool, + fallthrough: Option, + fallthrough_borrowed: Option, + collect_other_fields: bool, + expecting: Option<&str>, +) -> Fragment { + let str_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + let aliases = field.aliases; + let private2 = private; + // `aliases` also contains a main name + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + let bytes_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + // `aliases` also contains a main name + let aliases = field + .aliases + .iter() + .map(|alias| Literal::byte_string(alias.value.as_bytes())); + let private2 = private; + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + + let expecting = expecting.unwrap_or(if is_variant { + "variant identifier" + } else { + "field identifier" + }); + + let bytes_to_str = if fallthrough.is_some() || collect_other_fields { + None + } else { + Some(quote! { + let __value = &_serde::#private::from_utf8_lossy(__value); + }) + }; + + let ( + value_as_str_content, + value_as_borrowed_str_content, + value_as_bytes_content, + value_as_borrowed_bytes_content, + ) = if collect_other_fields { + ( + Some(quote! { + let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value)); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Str(__value); + }), + Some(quote! { + let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec()); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Bytes(__value); + }), + ) + } else { + (None, None, None, None) + }; + + let fallthrough_arm_tokens; + let fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else if is_variant { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) + }; + &fallthrough_arm_tokens + } else { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) + }; + &fallthrough_arm_tokens + }; + + let visit_other = if collect_other_fields { + quote! { + fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value))) + } + + fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value))) + } + + fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value))) + } + + fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value))) + } + + fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value))) + } + + fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value))) + } + + fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value))) + } + + fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value))) + } + + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value))) + } + + fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value))) + } + + fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value))) + } + + fn visit_char<__E>(self, __value: char) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value))) + } + + fn visit_unit<__E>(self) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit)) + } + } + } else { + let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| { + let i = i as u64; + let ident = &field.ident; + quote!(#i => _serde::#private::Ok(#this_value::#ident)) + }); + + let u64_fallthrough_arm_tokens; + let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else { + let index_expecting = if is_variant { "variant" } else { "field" }; + let fallthrough_msg = format!( + "{} index 0 <= i < {}", + index_expecting, + deserialized_fields.len(), + ); + u64_fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + }; + &u64_fallthrough_arm_tokens + }; + + quote! { + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#u64_mapping,)* + _ => #u64_fallthrough_arm, + } + } + } + }; + + let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { + let str_mapping = str_mapping.clone(); + let bytes_mapping = bytes_mapping.clone(); + let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); + Some(quote! { + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_borrowed_str_content + #fallthrough_borrowed_arm + } + } + } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_borrowed_arm + } + } + } + }) + } else { + None + }; + + quote_block! { + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_other + + fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_str_content + #fallthrough_arm + } + } + } + + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_bytes_content + #fallthrough_arm + } + } + } + + #visit_borrowed + } +} diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs new file mode 100644 index 000000000..6a5da232a --- /dev/null +++ b/serde_derive/src/de/struct_.rs @@ -0,0 +1,697 @@ +use crate::de::identifier; +use crate::de::{ + deserialize_seq, expr_is_missing, field_i, has_flatten, wrap_deserialize_field_with, + FieldWithAliases, Parameters, StructForm, +}; +#[cfg(feature = "deserialize_in_place")] +use crate::de::{deserialize_seq_in_place, place_lifetime}; +use crate::fragment::{Expr, Fragment, Match, Stmts}; +use crate::internals::ast::Field; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for a `struct Struct {...}` +pub(super) fn deserialize( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: StructForm, +) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this_value) + }; + + let type_path = match form { + StructForm::Struct => construct, + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident) + | StructForm::Untagged(variant_ident) => quote!(#construct::#variant_ident), + }; + let expecting = match form { + StructForm::Struct => format!("struct {}", params.type_name()), + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident) + | StructForm::Untagged(variant_ident) => { + format!("struct variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let deserialized_fields: Vec<_> = fields + .iter() + .enumerate() + // Skip fields that shouldn't be deserialized or that were flattened, + // so they don't appear in the storage in their literal form + .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(i, field)| FieldWithAliases { + ident: field_i(i), + aliases: field.attrs.aliases(), + }) + .collect(); + + let has_flatten = has_flatten(fields); + let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, has_flatten); + + // untagged struct variants do not get a visit_seq method. The same applies to + // structs that only have a map representation. + let visit_seq = match form { + StructForm::Untagged(_) => None, + _ if has_flatten => None, + _ => { + let mut_seq = if deserialized_fields.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, true, cattrs, expecting, + )); + + Some(quote! { + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + }) + } + }; + let visit_map = Stmts(deserialize_map( + &type_path, + params, + fields, + cattrs, + has_flatten, + )); + + let visitor_seed = match form { + StructForm::ExternallyTagged(..) if has_flatten => Some(quote! { + #[automatically_derived] + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<#delife>, + { + _serde::Deserializer::deserialize_map(__deserializer, self) + } + } + }), + _ => None, + }; + + let fields_stmt = if has_flatten { + None + } else { + let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); + + Some(quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + }) + }; + + let visitor_expr = quote! { + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + } + }; + let dispatch = match form { + StructForm::Struct if has_flatten => quote! { + _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) + }, + StructForm::Struct => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) + } + } + StructForm::ExternallyTagged(_) if has_flatten => quote! { + _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) + }, + StructForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) + }, + StructForm::InternallyTagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) + }, + StructForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) + }, + }; + + quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_seq + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #visitor_seed + + #fields_stmt + + #dispatch + } +} + +fn deserialize_map( + struct_path: &TokenStream, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + has_flatten: bool, +) -> Fragment { + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // Declare each field that will be deserialized. + let let_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let field_ty = field.ty; + quote! { + let mut #name: _serde::#private::Option<#field_ty> = _serde::#private::None; + } + }); + + // Collect contents for flatten fields into a buffer + let let_collect = if has_flatten { + Some(quote! { + let mut __collect = _serde::#private::Vec::<_serde::#private::Option<( + _serde::#private::de::Content, + _serde::#private::de::Content + )>>::new(); + }) + } else { + None + }; + + // Match arms to extract a value for a field. + let value_arms = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let deser_name = field.attrs.name().deserialize_name(); + + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); + quote! { + #func(&mut __map)? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::#private::Ok(__wrapper) => __wrapper.value, + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); + } + } + }) + } + }; + quote! { + __Field::#name => { + if _serde::#private::Option::is_some(&#name) { + return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #name = _serde::#private::Some(#visit); + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if has_flatten { + Some(quote! { + __Field::__other(__name) => { + __collect.push(_serde::#private::Some(( + __name, + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?))); + } + }) + } else if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::#private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { + match __key { + #(#value_arms)* + #ignored_arm + } + } + } + }; + + let extract_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let missing_expr = Match(expr_is_missing(field, cattrs)); + + quote! { + let #name = match #name { + _serde::#private::Some(#name) => #name, + _serde::#private::None => #missing_expr + }; + } + }); + + let extract_collected = fields_names + .iter() + .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let field_ty = field.ty; + let func = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + quote_spanned!(span=> _serde::de::Deserialize::deserialize) + } + Some(path) => quote!(#path), + }; + quote! { + let #name: #field_ty = #func( + _serde::#private::de::FlatMapDeserializer( + &mut __collect, + _serde::#private::PhantomData))?; + } + }); + + let collected_deny_unknown_fields = if has_flatten && cattrs.deny_unknown_fields() { + Some(quote! { + if let _serde::#private::Some(_serde::#private::Some((__key, _))) = + __collect.into_iter().filter(_serde::#private::Option::is_some).next() + { + if let _serde::#private::Some(__key) = _serde::#private::de::content_as_str(&__key) { + return _serde::#private::Err( + _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); + } else { + return _serde::#private::Err( + _serde::de::Error::custom(format_args!("unexpected map key"))); + } + } + }) + } else { + None + }; + + let result = fields_names.iter().map(|(field, name)| { + let member = &field.member; + if field.attrs.skip_deserializing() { + let value = Expr(expr_is_missing(field, cattrs)); + quote!(#member: #value) + } else { + quote!(#member: #name) + } + }); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::#private::Default::default(); + )), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> + let __default: Self::Value = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + let mut result = quote!(#struct_path { #(#result),* }); + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::#private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + quote_block! { + #(#let_values)* + + #let_collect + + #match_keys + + #let_default + + #(#extract_values)* + + #(#extract_collected)* + + #collected_deny_unknown_fields + + _serde::#private::Ok(#result) + } +} + +/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` +#[cfg(feature = "deserialize_in_place")] +pub(super) fn deserialize_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Option { + // for now we do not support in_place deserialization for structs that + // are represented as map. + if has_flatten(fields) { + return None; + } + + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let deserialized_fields: Vec<_> = fields + .iter() + .enumerate() + .filter(|&(_, field)| !field.attrs.skip_deserializing()) + .map(|(i, field)| FieldWithAliases { + ident: field_i(i), + aliases: field.attrs.aliases(), + }) + .collect(); + + let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, false); + + let mut_seq = if deserialized_fields.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); + let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); + let type_name = cattrs.name().deserialize_name(); + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + Some(quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this_type #ty_generics, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor { + place: __place, + lifetime: _serde::#private::PhantomData, + }) + }) +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_map_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!( + !has_flatten(fields), + "inplace deserialization of maps does not support flatten fields" + ); + + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // For deserialize_in_place, declare booleans for each field that will be + // deserialized. + let let_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(_, name)| { + quote! { + let mut #name: bool = false; + } + }); + + // Match arms to extract a value for a field. + let value_arms_from = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let deser_name = field.attrs.name().deserialize_name(); + let member = &field.member; + + let visit = match field.attrs.deserialize_with() { + None => { + quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::InPlaceSeed(&mut self.place.#member))? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::#private::Ok(__wrapper) => __wrapper.value, + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); + } + }; + }) + } + }; + quote! { + __Field::#name => { + if #name { + return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #visit; + #name = true; + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::#private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { + match __key { + #(#value_arms_from)* + #ignored_arm + } + } + } + }; + + let check_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let missing_expr = expr_is_missing(field, cattrs); + // If missing_expr unconditionally returns an error, don't try + // to assign its value to self.place. + if field.attrs.default().is_none() + && cattrs.default().is_none() + && field.attrs.deserialize_with().is_some() + { + let missing_expr = Stmts(missing_expr); + quote! { + if !#name { + #missing_expr; + } + } + } else { + let member = &field.member; + let missing_expr = Expr(missing_expr); + quote! { + if !#name { + self.place.#member = #missing_expr; + }; + } + } + }); + + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this_type #ty_generics = _serde::#private::Default::default(); + )), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> + let __default: #this_type #ty_generics = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + quote_block! { + #(#let_flags)* + + #match_keys + + #let_default + + #(#check_flags)* + + _serde::#private::Ok(()) + } +} + +/// Generates enum and its `Deserialize` implementation that represents each +/// non-skipped field of the struct +fn deserialize_field_identifier( + deserialized_fields: &[FieldWithAliases], + cattrs: &attr::Container, + has_flatten: bool, +) -> Stmts { + let (ignore_variant, fallthrough) = if has_flatten { + let ignore_variant = quote!(__other(_serde::#private::de::Content<'de>),); + let fallthrough = quote!(_serde::#private::Ok(__Field::__other(__value))); + (Some(ignore_variant), Some(fallthrough)) + } else if cattrs.deny_unknown_fields() { + (None, None) + } else { + let ignore_variant = quote!(__ignore,); + let fallthrough = quote!(_serde::#private::Ok(__Field::__ignore)); + (Some(ignore_variant), Some(fallthrough)) + }; + + Stmts(identifier::deserialize_generated( + deserialized_fields, + has_flatten, + false, + ignore_variant, + fallthrough, + )) +} diff --git a/serde_derive/src/de/tuple.rs b/serde_derive/src/de/tuple.rs new file mode 100644 index 000000000..a76089fe6 --- /dev/null +++ b/serde_derive/src/de/tuple.rs @@ -0,0 +1,283 @@ +use crate::de::{deserialize_seq, has_flatten, Parameters, TupleForm}; +#[cfg(feature = "deserialize_in_place")] +use crate::de::{deserialize_seq_in_place, place_lifetime}; +use crate::fragment::{Fragment, Stmts}; +use crate::internals::ast::Field; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);` +pub(super) fn deserialize( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: TupleForm, +) -> Fragment { + assert!( + !has_flatten(fields), + "tuples and tuple variants cannot have flatten fields" + ); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this_value) + }; + + let type_path = match form { + TupleForm::Tuple => construct, + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { + quote!(#construct::#variant_ident) + } + }; + let expecting = match form { + TupleForm::Tuple => format!("tuple struct {}", params.type_name()), + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { + format!("tuple variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = match form { + TupleForm::Tuple if nfields == 1 => { + Some(deserialize_newtype_struct(&type_path, params, &fields[0])) + } + _ => None, + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, false, cattrs, expecting, + )); + + let visitor_expr = quote! { + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + } + }; + let dispatch = match form { + TupleForm::Tuple if nfields == 1 => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr) + } + } + TupleForm::Tuple => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr) + } + } + TupleForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr) + }, + TupleForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr) + }, + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + quote_block! { + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +fn deserialize_newtype_struct( + type_path: &TokenStream, + params: &Parameters, + field: &Field, +) -> TokenStream { + let delife = params.borrowed.de_lifetime(); + let field_ty = field.ty; + let deserializer_var = quote!(__e); + + let value = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote! { + #func(#deserializer_var)? + } + } + Some(path) => { + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(with = "...")] + // ^^^^^ + quote_spanned! {path.span()=> + #path(#deserializer_var)? + } + } + }; + + let mut result = quote!(#type_path(__field0)); + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::#private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + quote! { + #[inline] + fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result + where + __E: _serde::Deserializer<#delife>, + { + let __field0: #field_ty = #value; + _serde::#private::Ok(#result) + } + } +} + +/// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` +#[cfg(feature = "deserialize_in_place")] +pub(super) fn deserialize_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!( + !has_flatten(fields), + "tuples and tuple variants cannot have flatten fields" + ); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("tuple struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = if nfields == 1 { + // We do not generate deserialize_in_place if every field has a + // deserialize_with. + assert!(fields[0].attrs.deserialize_with().is_none()); + + Some(quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::#private::Result + where + __E: _serde::Deserializer<#delife>, + { + _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) + } + }) + } else { + None + }; + + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::#private::PhantomData, + } + }; + + let type_name = cattrs.name().deserialize_name(); + let dispatch = if nfields == 1 { + quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) + } else { + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + quote_block! { + #[doc(hidden)] + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this_type #ty_generics, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} diff --git a/serde_derive/src/de/unit.rs b/serde_derive/src/de/unit.rs new file mode 100644 index 000000000..0d15ef4db --- /dev/null +++ b/serde_derive/src/de/unit.rs @@ -0,0 +1,52 @@ +use crate::de::Parameters; +use crate::fragment::Fragment; +use crate::internals::attr; +use crate::private; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for a `struct Unit;` +pub(super) fn deserialize(params: &Parameters, cattrs: &attr::Container) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let type_name = cattrs.name().deserialize_name(); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + params.generics_with_de_lifetime(); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("unit struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_unit<__E>(self) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(#this_value) + } + } + + _serde::Deserializer::deserialize_unit_struct( + __deserializer, + #type_name, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} diff --git a/serde_derive/src/deprecated.rs b/serde_derive/src/deprecated.rs new file mode 100644 index 000000000..3abdc1b25 --- /dev/null +++ b/serde_derive/src/deprecated.rs @@ -0,0 +1,56 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub fn allow_deprecated(input: &syn::DeriveInput) -> Option { + if should_allow_deprecated(input) { + Some(quote! { #[allow(deprecated)] }) + } else { + None + } +} + +/// Determine if an `#[allow(deprecated)]` should be added to the derived impl. +/// +/// This should happen if the derive input or an enum variant it contains has +/// one of: +/// - `#[deprecated]` +/// - `#[allow(deprecated)]` +fn should_allow_deprecated(input: &syn::DeriveInput) -> bool { + if contains_deprecated(&input.attrs) { + return true; + } + if let syn::Data::Enum(data_enum) = &input.data { + for variant in &data_enum.variants { + if contains_deprecated(&variant.attrs) { + return true; + } + } + } + false +} + +/// Check whether the given attributes contains one of: +/// - `#[deprecated]` +/// - `#[allow(deprecated)]` +fn contains_deprecated(attrs: &[syn::Attribute]) -> bool { + for attr in attrs { + if attr.path().is_ident("deprecated") { + return true; + } + if let syn::Meta::List(meta_list) = &attr.meta { + if meta_list.path.is_ident("allow") { + let mut allow_deprecated = false; + let _ = meta_list.parse_nested_meta(|meta| { + if meta.path.is_ident("deprecated") { + allow_deprecated = true; + } + Ok(()) + }); + if allow_deprecated { + return true; + } + } + } + } + false +} diff --git a/serde_derive/src/dummy.rs b/serde_derive/src/dummy.rs index 9a4e5f085..e0bca647a 100644 --- a/serde_derive/src/dummy.rs +++ b/serde_derive/src/dummy.rs @@ -1,48 +1,31 @@ -use proc_macro2::{Ident, TokenStream}; -use quote::format_ident; - -use syn; -use try; - -pub fn wrap_in_const( - serde_path: Option<&syn::Path>, - trait_: &str, - ty: &Ident, - code: TokenStream, -) -> TokenStream { - let try_replacement = try::replacement(); - - let dummy_const = if cfg!(underscore_consts) { - format_ident!("_") - } else { - format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty)) - }; +use proc_macro2::TokenStream; +use quote::quote; +pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream { let use_serde = match serde_path { Some(path) => quote! { use #path as _serde; }, None => quote! { - #[allow(rust_2018_idioms, clippy::useless_attribute)] + #[allow(unused_extern_crates, clippy::useless_attribute)] extern crate serde as _serde; }, }; quote! { #[doc(hidden)] - #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] - const #dummy_const: () = { + #[allow( + non_upper_case_globals, + unused_attributes, + unused_qualifications, + clippy::absolute_paths, + )] + const _: () = { #use_serde - #try_replacement + + _serde::__require_serde_not_serde_core!(); + #code }; } } - -#[allow(deprecated)] -fn unraw(ident: &Ident) -> String { - // str::trim_start_matches was added in 1.30, trim_left_matches deprecated - // in 1.33. We currently support rustc back to 1.15 so we need to continue - // to use the deprecated one. - ident.to_string().trim_left_matches("r#").to_owned() -} diff --git a/serde_derive/src/fragment.rs b/serde_derive/src/fragment.rs index 324504aa4..6627c2669 100644 --- a/serde_derive/src/fragment.rs +++ b/serde_derive/src/fragment.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::token; +use syn::{token, Token}; pub enum Fragment { /// Tokens that can be used as an expression. diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index 1afdaee54..5a760c657 100644 --- a/serde_derive/src/internals/ast.rs +++ b/serde_derive/src/internals/ast.rs @@ -1,10 +1,9 @@ //! A Serde ast, parsed from the Syn ast and ready to generate Rust code. -use internals::attr; -use internals::check; -use internals::{Ctxt, Derive}; -use syn; +use crate::internals::{attr, check, Ctxt, Derive}; +use proc_macro2::Ident; use syn::punctuated::Punctuated; +use syn::Token; /// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`, /// parsed into an internal representation. @@ -23,7 +22,7 @@ pub struct Container<'a> { /// The fields of a struct or enum. /// -/// Analagous to `syn::Data`. +/// Analogous to `syn::Data`. pub enum Data<'a> { Enum(Vec>), Struct(Style, Vec>), @@ -64,13 +63,17 @@ impl<'a> Container<'a> { cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive, + private: &Ident, ) -> Option> { - let mut attrs = attr::Container::from_ast(cx, item); + let attrs = attr::Container::from_ast(cx, item); let mut data = match &item.data { - syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())), + syn::Data::Enum(data) => { + Data::Enum(enum_from_ast(cx, &data.variants, attrs.default(), private)) + } syn::Data::Struct(data) => { - let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); + let (style, fields) = + struct_from_ast(cx, &data.fields, None, attrs.default(), private); Data::Struct(style, fields) } syn::Data::Union(_) => { @@ -79,35 +82,27 @@ impl<'a> Container<'a> { } }; - let mut has_flatten = false; match &mut data { Data::Enum(variants) => { for variant in variants { variant.attrs.rename_by_rules(attrs.rename_all_rules()); for field in &mut variant.fields { - if field.attrs.flatten() { - has_flatten = true; - } - field - .attrs - .rename_by_rules(variant.attrs.rename_all_rules()); + field.attrs.rename_by_rules( + variant + .attrs + .rename_all_rules() + .or(attrs.rename_all_fields_rules()), + ); } } } Data::Struct(_, fields) => { for field in fields { - if field.attrs.flatten() { - has_flatten = true; - } field.attrs.rename_by_rules(attrs.rename_all_rules()); } } } - if has_flatten { - attrs.mark_has_flatten(); - } - let mut item = Container { ident: item.ident.clone(), attrs, @@ -121,7 +116,7 @@ impl<'a> Container<'a> { } impl<'a> Data<'a> { - pub fn all_fields(&'a self) -> Box> + 'a> { + pub fn all_fields(&'a self) -> Box> + 'a> { match self { Data::Enum(variants) => { Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) @@ -139,13 +134,19 @@ fn enum_from_ast<'a>( cx: &Ctxt, variants: &'a Punctuated, container_default: &attr::Default, + private: &Ident, ) -> Vec> { - variants + let variants: Vec = variants .iter() .map(|variant| { let attrs = attr::Variant::from_ast(cx, variant); - let (style, fields) = - struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); + let (style, fields) = struct_from_ast( + cx, + &variant.fields, + Some(&attrs), + container_default, + private, + ); Variant { ident: variant.ident.clone(), attrs, @@ -154,7 +155,20 @@ fn enum_from_ast<'a>( original: variant, } }) - .collect() + .collect(); + + let index_of_last_tagged_variant = variants + .iter() + .rposition(|variant| !variant.attrs.untagged()); + if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant { + for variant in &variants[..index_of_last_tagged_variant] { + if variant.attrs.untagged() { + cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum"); + } + } + } + + variants } fn struct_from_ast<'a>( @@ -162,19 +176,20 @@ fn struct_from_ast<'a>( fields: &'a syn::Fields, attrs: Option<&attr::Variant>, container_default: &attr::Default, + private: &Ident, ) -> (Style, Vec>) { match fields { syn::Fields::Named(fields) => ( Style::Struct, - fields_from_ast(cx, &fields.named, attrs, container_default), + fields_from_ast(cx, &fields.named, attrs, container_default, private), ), syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => ( Style::Newtype, - fields_from_ast(cx, &fields.unnamed, attrs, container_default), + fields_from_ast(cx, &fields.unnamed, attrs, container_default, private), ), syn::Fields::Unnamed(fields) => ( Style::Tuple, - fields_from_ast(cx, &fields.unnamed, attrs, container_default), + fields_from_ast(cx, &fields.unnamed, attrs, container_default, private), ), syn::Fields::Unit => (Style::Unit, Vec::new()), } @@ -185,6 +200,7 @@ fn fields_from_ast<'a>( fields: &'a Punctuated, attrs: Option<&attr::Variant>, container_default: &attr::Default, + private: &Ident, ) -> Vec> { fields .iter() @@ -194,7 +210,7 @@ fn fields_from_ast<'a>( Some(ident) => syn::Member::Named(ident.clone()), None => syn::Member::Unnamed(i.into()), }, - attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), + attrs: attr::Field::from_ast(cx, i, field, attrs, container_default, private), ty: &field.ty, original: field, }) diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index e6f72dfe7..df0f33908 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -1,16 +1,15 @@ -use internals::symbol::*; -use internals::{ungroup, Ctxt}; -use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use crate::internals::name::{MultiName, Name}; +use crate::internals::symbol::*; +use crate::internals::{ungroup, Ctxt}; +use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; use quote::ToTokens; -use std::borrow::Cow; use std::collections::BTreeSet; -use std::str::FromStr; -use syn; -use syn::parse::{self, Parse, ParseStream}; +use std::iter::FromIterator; +use syn::meta::ParseNestedMeta; +use syn::parse::ParseStream; use syn::punctuated::Punctuated; -use syn::Ident; -use syn::Meta::{List, NameValue, Path}; -use syn::NestedMeta::{Lit, Meta}; +use syn::spanned::Spanned; +use syn::{token, Ident, Lifetime, Token}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and @@ -20,9 +19,9 @@ use syn::NestedMeta::{Lit, Meta}; // user will see errors simultaneously for all bad attributes in the crate // rather than just the first. -pub use internals::case::RenameRule; +pub use crate::internals::case::RenameRule; -struct Attr<'c, T> { +pub(crate) struct Attr<'c, T> { cx: &'c Ctxt, name: Symbol, tokens: TokenStream, @@ -43,8 +42,8 @@ impl<'c, T> Attr<'c, T> { let tokens = obj.into_token_stream(); if self.value.is_some() { - self.cx - .error_spanned_by(tokens, format!("duplicate serde attribute `{}`", self.name)); + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(tokens, msg); } else { self.tokens = tokens; self.value = Some(value); @@ -63,7 +62,7 @@ impl<'c, T> Attr<'c, T> { } } - fn get(self) -> Option { + pub(crate) fn get(self) -> Option { self.value } @@ -91,7 +90,7 @@ impl<'c> BoolAttr<'c> { } } -struct VecAttr<'c, T> { +pub(crate) struct VecAttr<'c, T> { cx: &'c Ctxt, name: Symbol, first_dup_tokens: TokenStream, @@ -115,103 +114,51 @@ impl<'c, T> VecAttr<'c, T> { self.values.push(value); } - fn at_most_one(mut self) -> Result, ()> { + fn at_most_one(mut self) -> Option { if self.values.len() > 1 { let dup_token = self.first_dup_tokens; - self.cx.error_spanned_by( - dup_token, - format!("duplicate serde attribute `{}`", self.name), - ); - Err(()) + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(dup_token, msg); + None } else { - Ok(self.values.pop()) + self.values.pop() } } - fn get(self) -> Vec { + pub(crate) fn get(self) -> Vec { self.values } } -pub struct Name { - serialize: String, - serialize_renamed: bool, - deserialize: String, - deserialize_renamed: bool, - deserialize_aliases: Vec, +fn unraw(ident: &Ident) -> Ident { + Ident::new(ident.to_string().trim_start_matches("r#"), ident.span()) } -#[allow(deprecated)] -fn unraw(ident: &Ident) -> String { - // str::trim_start_matches was added in 1.30, trim_left_matches deprecated - // in 1.33. We currently support rustc back to 1.15 so we need to continue - // to use the deprecated one. - ident.to_string().trim_left_matches("r#").to_owned() +#[derive(Copy, Clone)] +pub struct RenameAllRules { + pub serialize: RenameRule, + pub deserialize: RenameRule, } -impl Name { - fn from_attrs( - source_name: String, - ser_name: Attr, - de_name: Attr, - de_aliases: Option>, - ) -> Name { - let deserialize_aliases = match de_aliases { - Some(de_aliases) => { - let mut alias_list = BTreeSet::new(); - for alias_name in de_aliases.get() { - alias_list.insert(alias_name); - } - alias_list.into_iter().collect() - } - None => Vec::new(), - }; - - let ser_name = ser_name.get(); - let ser_renamed = ser_name.is_some(); - let de_name = de_name.get(); - let de_renamed = de_name.is_some(); - Name { - serialize: ser_name.unwrap_or_else(|| source_name.clone()), - serialize_renamed: ser_renamed, - deserialize: de_name.unwrap_or(source_name), - deserialize_renamed: de_renamed, - deserialize_aliases, - } - } - - /// Return the container name for the container when serializing. - pub fn serialize_name(&self) -> String { - self.serialize.clone() - } - - /// Return the container name for the container when deserializing. - pub fn deserialize_name(&self) -> String { - self.deserialize.clone() - } - - fn deserialize_aliases(&self) -> Vec { - let mut aliases = self.deserialize_aliases.clone(); - let main_name = self.deserialize_name(); - if !aliases.contains(&main_name) { - aliases.push(main_name); +impl RenameAllRules { + /// Returns a new `RenameAllRules` with the individual rules of `self` and + /// `other_rules` joined by `RenameRules::or`. + pub fn or(self, other_rules: Self) -> Self { + Self { + serialize: self.serialize.or(other_rules.serialize), + deserialize: self.deserialize.or(other_rules.deserialize), } - aliases } } -pub struct RenameAllRules { - serialize: RenameRule, - deserialize: RenameRule, -} - /// Represents struct or enum attribute information. pub struct Container { - name: Name, + name: MultiName, transparent: bool, deny_unknown_fields: bool, default: Default, rename_all_rules: RenameAllRules, + rename_all_fields_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, tag: TagType, @@ -220,9 +167,11 @@ pub struct Container { type_into: Option, remote: Option, identifier: Identifier, - has_flatten: bool, serde_path: Option, is_packed: bool, + /// Error message generated when type can't be deserialized + expecting: Option, + non_exhaustive: bool, } /// Styles of representing an enum. @@ -293,6 +242,8 @@ impl Container { let mut default = Attr::none(cx, DEFAULT); let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); + let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS); + let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS); let mut ser_bound = Attr::none(cx, BOUND); let mut de_bound = Attr::none(cx, BOUND); let mut untagged = BoolAttr::none(cx, UNTAGGED); @@ -305,297 +256,255 @@ impl Container { let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER); let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER); let mut serde_path = Attr::none(cx, CRATE); + let mut expecting = Attr::none(cx, EXPECTING); + let mut non_exhaustive = false; - for meta_item in item - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set(&m.path, s.value()); - } - } + for attr in &item.attrs { + if attr.path() != SERDE { + non_exhaustive |= + matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE); + continue; + } - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - de_name.set_opt(&m.path, de.map(syn::LitStr::value)); - } + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; } + } - // Parse `#[serde(rename_all = "foo")]` - Meta(NameValue(m)) if m.path == RENAME_ALL => { - if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { - match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => { - rename_all_ser_rule.set(&m.path, rename_rule); - rename_all_de_rule.set(&m.path, rename_rule); - } - Err(()) => cx.error_spanned_by( - s, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - s.value(), - ), - ), + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_renames(cx, RENAME, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); + de_name.set_opt(&meta.path, de.as_ref().map(Name::from)); + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), } } - } - - // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME_ALL => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - if let Some(ser) = ser { - match RenameRule::from_str(&ser.value()) { - Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), - Err(()) => cx.error_spanned_by( - ser, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - ser.value(), - ), - ), + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } } } - if let Some(de) = de { - match RenameRule::from_str(&de.value()) { - Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), - Err(()) => cx.error_spanned_by( - de, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - de.value(), - ), - ), + } + } else if meta.path == RENAME_ALL_FIELDS { + // #[serde(rename_all_fields = "foo")] + // #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?; + + match item.data { + syn::Data::Enum(_) => { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => { + rename_all_fields_ser_rule.set(&meta.path, rename_rule); + } + Err(err) => cx.error_spanned_by(ser, err), + } } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => { + rename_all_fields_de_rule.set(&meta.path, rename_rule); + } + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } + } + } + } + } + syn::Data::Struct(_) => { + let msg = "#[serde(rename_all_fields)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(rename_all_fields)] can only be used on enums"; + cx.syn_error(meta.error(msg)); } } - } - - // Parse `#[serde(transparent)]` - Meta(Path(word)) if word == TRANSPARENT => { - transparent.set_true(word); - } - - // Parse `#[serde(deny_unknown_fields)]` - Meta(Path(word)) if word == DENY_UNKNOWN_FIELDS => { - deny_unknown_fields.set_true(word); - } - - // Parse `#[serde(default)]` - Meta(Path(word)) if word == DEFAULT => match &item.data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { - syn::Fields::Named(_) => { - default.set(word, Default::Default); + } else if meta.path == TRANSPARENT { + // #[serde(transparent)] + transparent.set_true(meta.path); + } else if meta.path == DENY_UNKNOWN_FIELDS { + // #[serde(deny_unknown_fields)] + deny_unknown_fields.set_true(meta.path); + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + match &item.data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { + default.set(&meta.path, Default::Path(path)); + } + syn::Fields::Unit => { + let msg = "#[serde(default = \"...\")] can only be used on structs that have fields"; + cx.syn_error(meta.error(msg)); + } + }, + syn::Data::Enum(_) => { + let msg = "#[serde(default = \"...\")] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(default = \"...\")] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + } } - syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( - fields, - "#[serde(default)] can only be used on structs with named fields", - ), - }, - syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx.error_spanned_by( - enum_token, - "#[serde(default)] can only be used on structs with named fields", - ), - syn::Data::Union(syn::DataUnion { union_token, .. }) => cx.error_spanned_by( - union_token, - "#[serde(default)] can only be used on structs with named fields", - ), - }, - - // Parse `#[serde(default = "...")]` - Meta(NameValue(m)) if m.path == DEFAULT => { - if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { + } else { + // #[serde(default)] match &item.data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => { - match fields { - syn::Fields::Named(_) => { - default.set(&m.path, Default::Path(path)); - } - syn::Fields::Unnamed(_) | syn::Fields::Unit => cx - .error_spanned_by( - fields, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { + default.set(meta.path, Default::Default); } + syn::Fields::Unit => { + let msg = "#[serde(default)] can only be used on structs that have fields"; + cx.error_spanned_by(fields, msg); + } + }, + syn::Data::Enum(_) => { + let msg = "#[serde(default)] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(default)] can only be used on structs"; + cx.syn_error(meta.error(msg)); } - syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx - .error_spanned_by( - enum_token, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), - syn::Data::Union(syn::DataUnion { - union_token, .. - }) => cx.error_spanned_by( - union_token, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), } } - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); - } - } - - // Parse `#[serde(untagged)]` - Meta(Path(word)) if word == UNTAGGED => match item.data { - syn::Data::Enum(_) => { - untagged.set_true(word); - } - syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { - cx.error_spanned_by( - struct_token, - "#[serde(untagged)] can only be used on enums", - ); - } - syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(untagged)] can only be used on enums", - ); + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == UNTAGGED { + // #[serde(untagged)] + match item.data { + syn::Data::Enum(_) => { + untagged.set_true(&meta.path); + } + syn::Data::Struct(_) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } } - }, - - // Parse `#[serde(tag = "type")]` - Meta(NameValue(m)) if m.path == TAG => { - if let Ok(s) = get_lit_str(cx, TAG, &m.lit) { + } else if meta.path == TAG { + // #[serde(tag = "type")] + if let Some(s) = get_lit_str(cx, TAG, &meta)? { match &item.data { syn::Data::Enum(_) => { - internal_tag.set(&m.path, s.value()); + internal_tag.set(&meta.path, s.value()); } syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) => { - internal_tag.set(&m.path, s.value()); + internal_tag.set(&meta.path, s.value()); } syn::Fields::Unnamed(_) | syn::Fields::Unit => { - cx.error_spanned_by( - fields, - "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", - ); + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); } }, - syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", - ); + syn::Data::Union(_) => { + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); } } } - } - - // Parse `#[serde(content = "c")]` - Meta(NameValue(m)) if m.path == CONTENT => { - if let Ok(s) = get_lit_str(cx, CONTENT, &m.lit) { + } else if meta.path == CONTENT { + // #[serde(content = "c")] + if let Some(s) = get_lit_str(cx, CONTENT, &meta)? { match &item.data { syn::Data::Enum(_) => { - content.set(&m.path, s.value()); + content.set(&meta.path, s.value()); } - syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { - cx.error_spanned_by( - struct_token, - "#[serde(content = \"...\")] can only be used on enums", - ); + syn::Data::Struct(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); } - syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(content = \"...\")] can only be used on enums", - ); + syn::Data::Union(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); } } } - } - - // Parse `#[serde(from = "Type")] - Meta(NameValue(m)) if m.path == FROM => { - if let Ok(from_ty) = parse_lit_into_ty(cx, FROM, &m.lit) { - type_from.set_opt(&m.path, Some(from_ty)); + } else if meta.path == FROM { + // #[serde(from = "Type")] + if let Some(from_ty) = parse_lit_into_ty(cx, FROM, &meta)? { + type_from.set_opt(&meta.path, Some(from_ty)); } - } - - // Parse `#[serde(try_from = "Type")] - Meta(NameValue(m)) if m.path == TRY_FROM => { - if let Ok(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &m.lit) { - type_try_from.set_opt(&m.path, Some(try_from_ty)); + } else if meta.path == TRY_FROM { + // #[serde(try_from = "Type")] + if let Some(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &meta)? { + type_try_from.set_opt(&meta.path, Some(try_from_ty)); } - } - - // Parse `#[serde(into = "Type")] - Meta(NameValue(m)) if m.path == INTO => { - if let Ok(into_ty) = parse_lit_into_ty(cx, INTO, &m.lit) { - type_into.set_opt(&m.path, Some(into_ty)); + } else if meta.path == INTO { + // #[serde(into = "Type")] + if let Some(into_ty) = parse_lit_into_ty(cx, INTO, &meta)? { + type_into.set_opt(&meta.path, Some(into_ty)); } - } - - // Parse `#[serde(remote = "...")]` - Meta(NameValue(m)) if m.path == REMOTE => { - if let Ok(path) = parse_lit_into_path(cx, REMOTE, &m.lit) { + } else if meta.path == REMOTE { + // #[serde(remote = "...")] + if let Some(path) = parse_lit_into_path(cx, REMOTE, &meta)? { if is_primitive_path(&path, "Self") { - remote.set(&m.path, item.ident.clone().into()); + remote.set(&meta.path, item.ident.clone().into()); } else { - remote.set(&m.path, path); + remote.set(&meta.path, path); } } - } - - // Parse `#[serde(field_identifier)]` - Meta(Path(word)) if word == FIELD_IDENTIFIER => { - field_identifier.set_true(word); - } - - // Parse `#[serde(variant_identifier)]` - Meta(Path(word)) if word == VARIANT_IDENTIFIER => { - variant_identifier.set_true(word); - } - - // Parse `#[serde(crate = "foo")]` - Meta(NameValue(m)) if m.path == CRATE => { - if let Ok(path) = parse_lit_into_path(cx, CRATE, &m.lit) { - serde_path.set(&m.path, path) + } else if meta.path == FIELD_IDENTIFIER { + // #[serde(field_identifier)] + field_identifier.set_true(&meta.path); + } else if meta.path == VARIANT_IDENTIFIER { + // #[serde(variant_identifier)] + variant_identifier.set_true(&meta.path); + } else if meta.path == CRATE { + // #[serde(crate = "foo")] + if let Some(path) = parse_lit_into_path(cx, CRATE, &meta)? { + serde_path.set(&meta.path, path); } - } - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde container attribute `{}`", path), + } else if meta.path == EXPECTING { + // #[serde(expecting = "a message")] + if let Some(s) = get_lit_str(cx, EXPECTING, &meta)? { + expecting.set(&meta.path, s.value()); + } + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde container attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde container attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } let mut is_packed = false; for attr in &item.attrs { - if attr.path.is_ident("repr") { + if attr.path() == REPR { let _ = attr.parse_args_with(|input: ParseStream| { while let Some(token) = input.parse()? { if let TokenTree::Ident(ident) = token { @@ -608,7 +517,7 @@ impl Container { } Container { - name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), + name: MultiName::from_attrs(Name::from(&unraw(&item.ident)), ser_name, de_name, None), transparent: transparent.get(), deny_unknown_fields: deny_unknown_fields.get(), default: default.get().unwrap_or(Default::None), @@ -616,6 +525,10 @@ impl Container { serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), }, + rename_all_fields_rules: RenameAllRules { + serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None), + }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), tag: decide_tag(cx, item, untagged, internal_tag, content), @@ -624,18 +537,23 @@ impl Container { type_into: type_into.get(), remote: remote.get(), identifier: decide_identifier(cx, item, field_identifier, variant_identifier), - has_flatten: false, serde_path: serde_path.get(), is_packed, + expecting: expecting.get(), + non_exhaustive, } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } - pub fn rename_all_rules(&self) -> &RenameAllRules { - &self.rename_all_rules + pub fn rename_all_rules(&self) -> RenameAllRules { + self.rename_all_rules + } + + pub fn rename_all_fields_rules(&self) -> RenameAllRules { + self.rename_all_fields_rules } pub fn transparent(&self) -> bool { @@ -686,21 +604,18 @@ impl Container { self.identifier } - pub fn has_flatten(&self) -> bool { - self.has_flatten - } - - pub fn mark_has_flatten(&mut self) { - self.has_flatten = true; - } - pub fn custom_serde_path(&self) -> Option<&syn::Path> { self.serde_path.as_ref() } - pub fn serde_path(&self) -> Cow { - self.custom_serde_path() - .map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed) + /// Error message generated when type can't be deserialized. + /// If `None`, default message will be used + pub fn expecting(&self) -> Option<&str> { + self.expecting.as_ref().map(String::as_ref) + } + + pub fn non_exhaustive(&self) -> bool { + self.non_exhaustive } } @@ -726,10 +641,9 @@ fn decide_tag( syn::Fields::Named(_) | syn::Fields::Unit => {} syn::Fields::Unnamed(fields) => { if fields.unnamed.len() != 1 { - cx.error_spanned_by( - variant, - "#[serde(tag = \"...\")] cannot be used with tuple variants", - ); + let msg = + "#[serde(tag = \"...\")] cannot be used with tuple variants"; + cx.error_spanned_by(variant, msg); break; } } @@ -738,49 +652,29 @@ fn decide_tag( } TagType::Internal { tag } } - (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { - cx.error_spanned_by( - untagged_tokens, - "enum cannot be both untagged and internally tagged", - ); - cx.error_spanned_by( - tag_tokens, - "enum cannot be both untagged and internally tagged", - ); + (Some((untagged_tokens, ())), Some((tag_tokens, _)), None) => { + let msg = "enum cannot be both untagged and internally tagged"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); TagType::External // doesn't matter, will error } (None, None, Some((content_tokens, _))) => { - cx.error_spanned_by( - content_tokens, - "#[serde(tag = \"...\", content = \"...\")] must be used together", - ); + let msg = "#[serde(tag = \"...\", content = \"...\")] must be used together"; + cx.error_spanned_by(content_tokens, msg); TagType::External } - (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { - cx.error_spanned_by( - untagged_tokens, - "untagged enum cannot have #[serde(content = \"...\")]", - ); - cx.error_spanned_by( - content_tokens, - "untagged enum cannot have #[serde(content = \"...\")]", - ); + (Some((untagged_tokens, ())), None, Some((content_tokens, _))) => { + let msg = "untagged enum cannot have #[serde(content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(content_tokens, msg); TagType::External } (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content }, - (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { - cx.error_spanned_by( - untagged_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); - cx.error_spanned_by( - tag_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); - cx.error_spanned_by( - content_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); + (Some((untagged_tokens, ())), Some((tag_tokens, _)), Some((content_tokens, _))) => { + let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); + cx.error_spanned_by(content_tokens, msg); TagType::External } } @@ -798,45 +692,33 @@ fn decide_identifier( variant_identifier.0.get_with_tokens(), ) { (_, None, None) => Identifier::No, - (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { - cx.error_spanned_by( - field_identifier_tokens, - "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", - ); - cx.error_spanned_by( - variant_identifier_tokens, - "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", - ); + (_, Some((field_identifier_tokens, ())), Some((variant_identifier_tokens, ()))) => { + let msg = + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set"; + cx.error_spanned_by(field_identifier_tokens, msg); + cx.error_spanned_by(variant_identifier_tokens, msg); Identifier::No } (syn::Data::Enum(_), Some(_), None) => Identifier::Field, (syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, (syn::Data::Struct(syn::DataStruct { struct_token, .. }), Some(_), None) => { - cx.error_spanned_by( - struct_token, - "#[serde(field_identifier)] can only be used on an enum", - ); + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), Some(_), None) => { - cx.error_spanned_by( - union_token, - "#[serde(field_identifier)] can only be used on an enum", - ); + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); Identifier::No } (syn::Data::Struct(syn::DataStruct { struct_token, .. }), None, Some(_)) => { - cx.error_spanned_by( - struct_token, - "#[serde(variant_identifier)] can only be used on an enum", - ); + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), None, Some(_)) => { - cx.error_spanned_by( - union_token, - "#[serde(variant_identifier)] can only be used on an enum", - ); + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); Identifier::No } } @@ -844,7 +726,7 @@ fn decide_identifier( /// Represents variant attribute information pub struct Variant { - name: Name, + name: MultiName, rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, @@ -853,7 +735,13 @@ pub struct Variant { other: bool, serialize_with: Option, deserialize_with: Option, - borrow: Option, + borrow: Option, + untagged: bool, +} + +struct BorrowAttribute { + path: syn::Path, + lifetimes: Option>, } impl Variant { @@ -871,192 +759,145 @@ impl Variant { let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); let mut borrow = Attr::none(cx, BORROW); + let mut untagged = BoolAttr::none(cx, UNTAGGED); - for meta_item in variant - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set_if_none(s.value()); - de_aliases.insert(&m.path, s.value()); - } - } + for attr in &variant.attrs { + if attr.path() != SERDE { + continue; + } - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&m.path, de_value.value()); - } - } + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; } + } - // Parse `#[serde(alias = "foo")]` - Meta(NameValue(m)) if m.path == ALIAS => { - if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { - de_aliases.insert(&m.path, s.value()); + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); + for de_value in de { + de_name.set_if_none(Name::from(&de_value)); + de_aliases.insert(&meta.path, Name::from(&de_value)); } - } - - // Parse `#[serde(rename_all = "foo")]` - Meta(NameValue(m)) if m.path == RENAME_ALL => { - if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { - match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => { - rename_all_ser_rule.set(&m.path, rename_rule); - rename_all_de_rule.set(&m.path, rename_rule); - } - Err(()) => cx.error_spanned_by( - s, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - s.value() - ), - ), - } + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, Name::from(&s)); } - } - - // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME_ALL => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - if let Some(ser) = ser { - match RenameRule::from_str(&ser.value()) { - Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), - Err(()) => cx.error_spanned_by( - ser, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - ser.value(), - ), - ), - } + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), } - if let Some(de) = de { - match RenameRule::from_str(&de.value()) { - Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), - Err(()) => cx.error_spanned_by( - de, - format!( - "unknown rename rule for #[serde(rename_all = {:?})]", - de.value(), - ), - ), + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } } } } - } - - // Parse `#[serde(skip)]` - Meta(Path(word)) if word == SKIP => { - skip_serializing.set_true(word); - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_deserializing)]` - Meta(Path(word)) if word == SKIP_DESERIALIZING => { - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_serializing)]` - Meta(Path(word)) if word == SKIP_SERIALIZING => { - skip_serializing.set_true(word); - } - - // Parse `#[serde(other)]` - Meta(Path(word)) if word == OTHER => { - other.set_true(word); - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); - } - } - - // Parse `#[serde(with = "...")]` - Meta(NameValue(m)) if m.path == WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == OTHER { + // #[serde(other)] + other.set_true(&meta.path); + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { let mut ser_path = path.clone(); ser_path .path .segments - .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(&m.path, ser_path); + .push(Ident::new("serialize", ser_path.span()).into()); + serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments - .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(&m.path, de_path); + .push(Ident::new("deserialize", de_path.span()).into()); + deserialize_with.set(&meta.path, de_path); } - } - - // Parse `#[serde(serialize_with = "...")]` - Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { - serialize_with.set(&m.path, path); + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); } - } - - // Parse `#[serde(deserialize_with = "...")]` - Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { - deserialize_with.set(&m.path, path); + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); } - } - - // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` - Meta(m) if m.path() == BORROW => match &variant.fields { - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { - borrow.set(m.path(), m.clone()); - } - _ => { - cx.error_spanned_by( - variant, - "#[serde(borrow)] may only be used on newtype variants", - ); + } else if meta.path == BORROW { + let borrow_attribute = if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; + BorrowAttribute { + path: meta.path.clone(), + lifetimes: Some(lifetimes), + } + } else { + // #[serde(borrow)] + BorrowAttribute { + path: meta.path.clone(), + lifetimes: None, + } + }; + match &variant.fields { + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + borrow.set(&meta.path, borrow_attribute); + } + _ => { + let msg = "#[serde(borrow)] may only be used on newtype variants"; + cx.error_spanned_by(variant, msg); + } } - }, - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde variant attribute `{}`", path), + } else if meta.path == UNTAGGED { + untagged.set_true(&meta.path); + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde variant attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde variant attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } Variant { - name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), + name: MultiName::from_attrs( + Name::from(&unraw(&variant.ident)), + ser_name, + de_name, + Some(de_aliases), + ), rename_all_rules: RenameAllRules { serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), @@ -1069,28 +910,35 @@ impl Variant { serialize_with: serialize_with.get(), deserialize_with: deserialize_with.get(), borrow: borrow.get(), + untagged: untagged.get(), } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } - pub fn aliases(&self) -> Vec { + pub fn aliases(&self) -> &BTreeSet { self.name.deserialize_aliases() } - pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { if !self.name.serialize_renamed { - self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); + self.name.serialize.value = + rules.serialize.apply_to_variant(&self.name.serialize.value); } if !self.name.deserialize_renamed { - self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); + self.name.deserialize.value = rules + .deserialize + .apply_to_variant(&self.name.deserialize.value); } + self.name + .deserialize_aliases + .insert(self.name.deserialize.clone()); } - pub fn rename_all_rules(&self) -> &RenameAllRules { - &self.rename_all_rules + pub fn rename_all_rules(&self) -> RenameAllRules { + self.rename_all_rules } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { @@ -1120,11 +968,15 @@ impl Variant { pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { self.deserialize_with.as_ref() } + + pub fn untagged(&self) -> bool { + self.untagged + } } /// Represents field attribute information pub struct Field { - name: Name, + name: MultiName, skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, @@ -1166,6 +1018,7 @@ impl Field { field: &syn::Field, attrs: Option<&Variant>, container_default: &Default, + private: &Ident, ) -> Self { let mut ser_name = Attr::none(cx, RENAME); let mut de_name = Attr::none(cx, RENAME); @@ -1183,196 +1036,160 @@ impl Field { let mut flatten = BoolAttr::none(cx, FLATTEN); let ident = match &field.ident { - Some(ident) => unraw(ident), - None => index.to_string(), + Some(ident) => Name::from(&unraw(ident)), + None => Name { + value: index.to_string(), + span: Span::call_site(), + }, }; - let variant_borrow = attrs - .and_then(|variant| variant.borrow.as_ref()) - .map(|borrow| Meta(borrow.clone())); - - for meta_item in field - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - .chain(variant_borrow) - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set_if_none(s.value()); - de_aliases.insert(&m.path, s.value()); - } - } - - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&m.path, de_value.value()); + if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + if let Some(lifetimes) = &borrow_attribute.lifetimes { + for lifetime in lifetimes { + if !borrowable.contains(lifetime) { + let msg = + format!("field `{}` does not have lifetime {}", ident, lifetime); + cx.error_spanned_by(field, msg); } } + borrowed_lifetimes.set(&borrow_attribute.path, lifetimes.clone()); + } else { + borrowed_lifetimes.set(&borrow_attribute.path, borrowable); } + } + } - // Parse `#[serde(alias = "foo")]` - Meta(NameValue(m)) if m.path == ALIAS => { - if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { - de_aliases.insert(&m.path, s.value()); - } - } + for attr in &field.attrs { + if attr.path() != SERDE { + continue; + } - // Parse `#[serde(default)]` - Meta(Path(word)) if word == DEFAULT => { - default.set(word, Default::Default); + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; } + } - // Parse `#[serde(default = "...")]` - Meta(NameValue(m)) if m.path == DEFAULT => { - if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { - default.set(&m.path, Default::Path(path)); + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); + for de_value in de { + de_name.set_if_none(Name::from(&de_value)); + de_aliases.insert(&meta.path, Name::from(&de_value)); } - } - - // Parse `#[serde(skip_serializing)]` - Meta(Path(word)) if word == SKIP_SERIALIZING => { - skip_serializing.set_true(word); - } - - // Parse `#[serde(skip_deserializing)]` - Meta(Path(word)) if word == SKIP_DESERIALIZING => { - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip)]` - Meta(Path(word)) if word == SKIP => { - skip_serializing.set_true(word); - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_serializing_if = "...")]` - Meta(NameValue(m)) if m.path == SKIP_SERIALIZING_IF => { - if let Ok(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &m.lit) { - skip_serializing_if.set(&m.path, path); + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, Name::from(&s)); } - } - - // Parse `#[serde(serialize_with = "...")]` - Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { - serialize_with.set(&m.path, path); + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + default.set(&meta.path, Default::Path(path)); + } + } else { + // #[serde(default)] + default.set(&meta.path, Default::Default); } - } - - // Parse `#[serde(deserialize_with = "...")]` - Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { - deserialize_with.set(&m.path, path); + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING_IF { + // #[serde(skip_serializing_if = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &meta)? { + skip_serializing_if.set(&meta.path, path); } - } - - // Parse `#[serde(with = "...")]` - Meta(NameValue(m)) if m.path == WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); + } + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); + } + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { let mut ser_path = path.clone(); ser_path .path .segments - .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(&m.path, ser_path); + .push(Ident::new("serialize", ser_path.span()).into()); + serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments - .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(&m.path, de_path); - } - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); - } - } - - // Parse `#[serde(borrow)]` - Meta(Path(word)) if word == BORROW => { - if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { - borrowed_lifetimes.set(word, borrowable); + .push(Ident::new("deserialize", de_path.span()).into()); + deserialize_with.set(&meta.path, de_path); } - } - - // Parse `#[serde(borrow = "'a + 'b")]` - Meta(NameValue(m)) if m.path == BORROW => { - if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, BORROW, &m.lit) { + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == BORROW { + if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { - cx.error_spanned_by( - field, - format!( - "field `{}` does not have lifetime {}", - ident, lifetime - ), + let msg = format!( + "field `{}` does not have lifetime {}", + ident, lifetime, ); + cx.error_spanned_by(field, msg); } } - borrowed_lifetimes.set(&m.path, lifetimes); + borrowed_lifetimes.set(&meta.path, lifetimes); + } + } else { + // #[serde(borrow)] + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(&meta.path, borrowable); } } - } - - // Parse `#[serde(getter = "...")]` - Meta(NameValue(m)) if m.path == GETTER => { - if let Ok(path) = parse_lit_into_expr_path(cx, GETTER, &m.lit) { - getter.set(&m.path, path); + } else if meta.path == GETTER { + // #[serde(getter = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, GETTER, &meta)? { + getter.set(&meta.path, path); } - } - - // Parse `#[serde(flatten)]` - Meta(Path(word)) if word == FLATTEN => { - flatten.set_true(word); - } - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde field attribute `{}`", path), + } else if meta.path == FLATTEN { + // #[serde(flatten)] + flatten.set_true(&meta.path); + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde field attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde field attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } - // Is skip_deserializing, initialize the field to Default::default() unless a + // If skip_deserializing, initialize the field to Default::default() unless a // different default is specified by `#[serde(default = "...")]` on // ourselves or our container (e.g. the struct we are in). - if let Default::None = *container_default { - if skip_deserializing.0.value.is_some() { - default.set_if_none(Default::Default); - } + if container_default.is_none() && skip_deserializing.0.value.is_some() { + default.set_if_none(Default::Default); } let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); @@ -1393,7 +1210,7 @@ impl Field { }; let span = Span::call_site(); path.segments.push(Ident::new("_serde", span).into()); - path.segments.push(Ident::new("private", span).into()); + path.segments.push(private.clone().into()); path.segments.push(Ident::new("de", span).into()); path.segments .push(Ident::new("borrow_cow_str", span).into()); @@ -1410,7 +1227,7 @@ impl Field { }; let span = Span::call_site(); path.segments.push(Ident::new("_serde", span).into()); - path.segments.push(Ident::new("private", span).into()); + path.segments.push(private.clone().into()); path.segments.push(Ident::new("de", span).into()); path.segments .push(Ident::new("borrow_cow_bytes", span).into()); @@ -1428,7 +1245,7 @@ impl Field { } Field { - name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), + name: MultiName::from_attrs(ident, ser_name, de_name, Some(de_aliases)), skip_serializing: skip_serializing.get(), skip_deserializing: skip_deserializing.get(), skip_serializing_if: skip_serializing_if.get(), @@ -1444,21 +1261,26 @@ impl Field { } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } - pub fn aliases(&self) -> Vec { + pub fn aliases(&self) -> &BTreeSet { self.name.deserialize_aliases() } - pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { if !self.name.serialize_renamed { - self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); + self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value); } if !self.name.deserialize_renamed { - self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); + self.name.deserialize.value = rules + .deserialize + .apply_to_field(&self.name.deserialize.value); } + self.name + .deserialize_aliases + .insert(self.name.deserialize.clone()); } pub fn skip_serializing(&self) -> bool { @@ -1516,130 +1338,159 @@ impl Field { type SerAndDe = (Option, Option); -fn get_ser_and_de<'a, 'b, T, F>( - cx: &'b Ctxt, +fn get_ser_and_de<'c, T, F, R>( + cx: &'c Ctxt, attr_name: Symbol, - metas: &'a Punctuated, + meta: &ParseNestedMeta, f: F, -) -> Result<(VecAttr<'b, T>, VecAttr<'b, T>), ()> +) -> syn::Result<(VecAttr<'c, T>, VecAttr<'c, T>)> where - T: 'a, - F: Fn(&Ctxt, Symbol, Symbol, &'a syn::Lit) -> Result, + T: Clone, + F: Fn(&Ctxt, Symbol, Symbol, &ParseNestedMeta) -> syn::Result, + R: Into>, { let mut ser_meta = VecAttr::none(cx, attr_name); let mut de_meta = VecAttr::none(cx, attr_name); - for meta in metas { - match meta { - Meta(NameValue(meta)) if meta.path == SERIALIZE => { - if let Ok(v) = f(cx, attr_name, SERIALIZE, &meta.lit) { + let lookahead = meta.input.lookahead1(); + if lookahead.peek(Token![=]) { + if let Some(both) = f(cx, attr_name, attr_name, meta)?.into() { + ser_meta.insert(&meta.path, both.clone()); + de_meta.insert(&meta.path, both); + } + } else if lookahead.peek(token::Paren) { + meta.parse_nested_meta(|meta| { + if meta.path == SERIALIZE { + if let Some(v) = f(cx, attr_name, SERIALIZE, &meta)?.into() { ser_meta.insert(&meta.path, v); } - } - - Meta(NameValue(meta)) if meta.path == DESERIALIZE => { - if let Ok(v) = f(cx, attr_name, DESERIALIZE, &meta.lit) { + } else if meta.path == DESERIALIZE { + if let Some(v) = f(cx, attr_name, DESERIALIZE, &meta)?.into() { de_meta.insert(&meta.path, v); } + } else { + return Err(meta.error(format_args!( + "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", + attr_name, + ))); } - - _ => { - cx.error_spanned_by( - meta, - format!( - "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", - attr_name - ), - ); - return Err(()); - } - } + Ok(()) + })?; + } else { + return Err(lookahead.error()); } Ok((ser_meta, de_meta)) } -fn get_renames<'a>( +fn get_renames( cx: &Ctxt, - items: &'a Punctuated, -) -> Result, ()> { - let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; - Ok((ser.at_most_one()?, de.at_most_one()?)) + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let (ser, de) = get_ser_and_de(cx, attr_name, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.at_most_one())) } -fn get_multiple_renames<'a>( +fn get_multiple_renames( cx: &Ctxt, - items: &'a Punctuated, -) -> Result<(Option<&'a syn::LitStr>, Vec<&'a syn::LitStr>), ()> { - let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; - Ok((ser.at_most_one()?, de.get())) + meta: &ParseNestedMeta, +) -> syn::Result<(Option, Vec)> { + let (ser, de) = get_ser_and_de(cx, RENAME, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.get())) } fn get_where_predicates( cx: &Ctxt, - items: &Punctuated, -) -> Result>, ()> { - let (ser, de) = get_ser_and_de(cx, BOUND, items, parse_lit_into_where)?; - Ok((ser.at_most_one()?, de.at_most_one()?)) + meta: &ParseNestedMeta, +) -> syn::Result>> { + let (ser, de) = get_ser_and_de(cx, BOUND, meta, parse_lit_into_where)?; + Ok((ser.at_most_one(), de.at_most_one())) } -pub fn get_serde_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result, ()> { - if attr.path != SERDE { - return Ok(Vec::new()); - } - - match attr.parse_meta() { - Ok(List(meta)) => Ok(meta.nested.into_iter().collect()), - Ok(other) => { - cx.error_spanned_by(other, "expected #[serde(...)]"); - Err(()) - } - Err(err) => { - cx.syn_error(err); - Err(()) - } - } -} - -fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'a syn::LitStr, ()> { - get_lit_str2(cx, attr_name, attr_name, lit) +fn get_lit_str( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + get_lit_str2(cx, attr_name, attr_name, meta) } -fn get_lit_str2<'a>( +fn get_lit_str2( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, - lit: &'a syn::Lit, -) -> Result<&'a syn::LitStr, ()> { - if let syn::Lit::Str(lit) = lit { - Ok(lit) + meta: &ParseNestedMeta, +) -> syn::Result> { + let expr: syn::Expr = meta.value()?.parse()?; + let mut value = &expr; + while let syn::Expr::Group(e) = value { + value = &e.expr; + } + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }) = value + { + let suffix = lit.suffix(); + if !suffix.is_empty() { + cx.error_spanned_by( + lit, + format!("unexpected suffix `{}` on string literal", suffix), + ); + } + Ok(Some(lit.clone())) } else { cx.error_spanned_by( - lit, + expr, format!( "expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name ), ); - Err(()) + Ok(None) } } -fn parse_lit_into_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { - let string = get_lit_str(cx, attr_name, lit)?; - parse_lit_str(string).map_err(|_| { - cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) +fn parse_lit_into_path( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, attr_name, meta)? else { + return Ok(None); + }; + + Ok(match string.parse() { + Ok(path) => Some(path), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } }) } fn parse_lit_into_expr_path( cx: &Ctxt, attr_name: Symbol, - lit: &syn::Lit, -) -> Result { - let string = get_lit_str(cx, attr_name, lit)?; - parse_lit_str(string).map_err(|_| { - cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, attr_name, meta)? else { + return Ok(None); + }; + + Ok(match string.parse() { + Ok(expr) => Some(expr), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } }) } @@ -1647,28 +1498,41 @@ fn parse_lit_into_where( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, - lit: &syn::Lit, -) -> Result, ()> { - let string = get_lit_str2(cx, attr_name, meta_item_name, lit)?; - if string.value().is_empty() { + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str2(cx, attr_name, meta_item_name, meta)? else { return Ok(Vec::new()); - } - - let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span()); + }; - parse_lit_str::(&where_string) - .map(|wh| wh.predicates.into_iter().collect()) - .map_err(|err| cx.error_spanned_by(lit, err)) + Ok( + match string.parse_with(Punctuated::::parse_terminated) { + Ok(predicates) => Vec::from_iter(predicates), + Err(err) => { + cx.error_spanned_by(string, err); + Vec::new() + } + }, + ) } -fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { - let string = get_lit_str(cx, attr_name, lit)?; +fn parse_lit_into_ty( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, attr_name, meta)? else { + return Ok(None); + }; - parse_lit_str(string).map_err(|_| { - cx.error_spanned_by( - lit, - format!("failed to parse type: {} = {:?}", attr_name, string.value()), - ) + Ok(match string.parse() { + Ok(ty) => Some(ty), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse type: {} = {:?}", attr_name, string.value()), + ); + None + } }) } @@ -1676,38 +1540,40 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result Result, ()> { - let string = get_lit_str(cx, attr_name, lit)?; - if string.value().is_empty() { - cx.error_spanned_by(lit, "at least one lifetime must be borrowed"); - return Err(()); - } - - struct BorrowedLifetimes(Punctuated); - - impl Parse for BorrowedLifetimes { - fn parse(input: ParseStream) -> parse::Result { - Punctuated::parse_separated_nonempty(input).map(BorrowedLifetimes) - } - } + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, BORROW, meta)? else { + return Ok(BTreeSet::new()); + }; - if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { + if let Ok(lifetimes) = string.parse_with(|input: ParseStream| { let mut set = BTreeSet::new(); - for lifetime in lifetimes { + while !input.is_empty() { + let lifetime: Lifetime = input.parse()?; if !set.insert(lifetime.clone()) { - cx.error_spanned_by(lit, format!("duplicate borrowed lifetime `{}`", lifetime)); + cx.error_spanned_by( + &string, + format!("duplicate borrowed lifetime `{}`", lifetime), + ); + } + if input.is_empty() { + break; } + input.parse::()?; } - return Ok(set); + Ok(set) + }) { + if lifetimes.is_empty() { + cx.error_spanned_by(string, "at least one lifetime must be borrowed"); + } + return Ok(lifetimes); } cx.error_spanned_by( - lit, + &string, format!("failed to parse borrowed lifetimes: {:?}", string.value()), ); - Err(()) + Ok(BTreeSet::new()) } fn is_implicitly_borrowed(ty: &syn::Type) -> bool { @@ -1747,11 +1613,8 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { return false; } }; - let seg = match path.segments.last() { - Some(seg) => seg, - None => { - return false; - } + let Some(seg) = path.segments.last() else { + return false; }; let args = match &seg.arguments { syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, @@ -1774,11 +1637,8 @@ fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { return false; } }; - let seg = match path.segments.last() { - Some(seg) => seg, - None => { - return false; - } + let Some(seg) = path.segments.last() else { + return false; }; let args = match &seg.arguments { syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, @@ -1855,16 +1715,14 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { // attribute on the field so there must be at least one borrowable lifetime. fn borrowable_lifetimes( cx: &Ctxt, - name: &str, + name: &Name, field: &syn::Field, ) -> Result, ()> { let mut lifetimes = BTreeSet::new(); collect_lifetimes(&field.ty, &mut lifetimes); if lifetimes.is_empty() { - cx.error_spanned_by( - field, - format!("field `{}` has no lifetimes to borrow", name), - ); + let msg = format!("field `{}` has no lifetimes to borrow", name); + cx.error_spanned_by(field, msg); Err(()) } else { Ok(lifetimes) @@ -1873,6 +1731,7 @@ fn borrowable_lifetimes( fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] syn::Type::Slice(ty) => { collect_lifetimes(&ty.elem, out); } @@ -1905,11 +1764,13 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { syn::GenericArgument::Type(ty) => { collect_lifetimes(ty, out); } - syn::GenericArgument::Binding(binding) => { + syn::GenericArgument::AssocType(binding) => { collect_lifetimes(&binding.ty, out); } - syn::GenericArgument::Constraint(_) - | syn::GenericArgument::Const(_) => {} + syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) + | _ => {} } } } @@ -1921,41 +1782,37 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { syn::Type::Group(ty) => { collect_lifetimes(&ty.elem, out); } + syn::Type::Macro(ty) => { + collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); + } syn::Type::BareFn(_) | syn::Type::Never(_) | syn::Type::TraitObject(_) | syn::Type::ImplTrait(_) | syn::Type::Infer(_) - | syn::Type::Macro(_) - | syn::Type::Verbatim(_) - | _ => {} - } -} + | syn::Type::Verbatim(_) => {} -fn parse_lit_str(s: &syn::LitStr) -> parse::Result -where - T: Parse, -{ - let tokens = spanned_tokens(s)?; - syn::parse2(tokens) -} - -fn spanned_tokens(s: &syn::LitStr) -> parse::Result { - let stream = syn::parse_str(&s.value())?; - Ok(respan_token_stream(stream, s.span())) -} - -fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { - stream - .into_iter() - .map(|token| respan_token_tree(token, span)) - .collect() + _ => {} + } } -fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { - if let TokenTree::Group(g) = &mut token { - *g = Group::new(g.delimiter(), respan_token_stream(g.stream(), span)); +fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet) { + let mut iter = tokens.into_iter(); + while let Some(tt) = iter.next() { + match &tt { + TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + if let Some(TokenTree::Ident(ident)) = iter.next() { + out.insert(syn::Lifetime { + apostrophe: op.span(), + ident, + }); + } + } + TokenTree::Group(group) => { + let tokens = group.stream(); + collect_lifetimes_from_tokens(tokens, out); + } + _ => {} + } } - token.set_span(span); - token } diff --git a/serde_derive/src/internals/case.rs b/serde_derive/src/internals/case.rs index 3fcbb32db..8c8c02e75 100644 --- a/serde_derive/src/internals/case.rs +++ b/serde_derive/src/internals/case.rs @@ -1,13 +1,8 @@ //! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the //! case of the source (e.g. `my-field`, `MY_FIELD`). -// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726 -#[allow(deprecated, unused_imports)] -use std::ascii::AsciiExt; - -use std::str::FromStr; - use self::RenameRule::*; +use std::fmt::{self, Debug, Display}; /// The different possible ways to change case of fields in a struct, or variants in an enum. #[derive(Copy, Clone, PartialEq)] @@ -17,7 +12,7 @@ pub enum RenameRule { /// Rename direct children to "lowercase" style. LowerCase, /// Rename direct children to "UPPERCASE" style. - UPPERCASE, + UpperCase, /// Rename direct children to "PascalCase" style, as typically used for /// enum variants. PascalCase, @@ -35,13 +30,35 @@ pub enum RenameRule { ScreamingKebabCase, } +static RENAME_RULES: &[(&str, RenameRule)] = &[ + ("lowercase", LowerCase), + ("UPPERCASE", UpperCase), + ("PascalCase", PascalCase), + ("camelCase", CamelCase), + ("snake_case", SnakeCase), + ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), + ("kebab-case", KebabCase), + ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), +]; + impl RenameRule { + pub fn from_str(rename_all_str: &str) -> Result { + for (name, rule) in RENAME_RULES { + if rename_all_str == *name { + return Ok(*rule); + } + } + Err(ParseError { + unknown: rename_all_str, + }) + } + /// Apply a renaming rule to an enum variant, returning the version expected in the source. - pub fn apply_to_variant(&self, variant: &str) -> String { - match *self { + pub fn apply_to_variant(self, variant: &str) -> String { + match self { None | PascalCase => variant.to_owned(), LowerCase => variant.to_ascii_lowercase(), - UPPERCASE => variant.to_ascii_uppercase(), + UpperCase => variant.to_ascii_uppercase(), CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], SnakeCase => { let mut snake = String::new(); @@ -62,10 +79,10 @@ impl RenameRule { } /// Apply a renaming rule to a struct field, returning the version expected in the source. - pub fn apply_to_field(&self, field: &str) -> String { - match *self { + pub fn apply_to_field(self, field: &str) -> String { + match self { None | LowerCase | SnakeCase => field.to_owned(), - UPPERCASE => field.to_ascii_uppercase(), + UpperCase => field.to_ascii_uppercase(), PascalCase => { let mut pascal = String::new(); let mut capitalize = true; @@ -90,23 +107,32 @@ impl RenameRule { ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), } } + + /// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise. + pub fn or(self, rule_b: Self) -> Self { + match self { + None => rule_b, + _ => self, + } + } } -impl FromStr for RenameRule { - type Err = (); +pub struct ParseError<'a> { + unknown: &'a str, +} - fn from_str(rename_all_str: &str) -> Result { - match rename_all_str { - "lowercase" => Ok(LowerCase), - "UPPERCASE" => Ok(UPPERCASE), - "PascalCase" => Ok(PascalCase), - "camelCase" => Ok(CamelCase), - "snake_case" => Ok(SnakeCase), - "SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase), - "kebab-case" => Ok(KebabCase), - "SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase), - _ => Err(()), +impl<'a> Display for ParseError<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("unknown rename rule `rename_all = ")?; + Debug::fmt(self.unknown, f)?; + f.write_str("`, expected one of ")?; + for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + Debug::fmt(name, f)?; } + Ok(()) } } @@ -131,7 +157,7 @@ fn rename_variants() { ] { assert_eq!(None.apply_to_variant(original), original); assert_eq!(LowerCase.apply_to_variant(original), lower); - assert_eq!(UPPERCASE.apply_to_variant(original), upper); + assert_eq!(UpperCase.apply_to_variant(original), upper); assert_eq!(PascalCase.apply_to_variant(original), original); assert_eq!(CamelCase.apply_to_variant(original), camel); assert_eq!(SnakeCase.apply_to_variant(original), snake); @@ -163,7 +189,7 @@ fn rename_fields() { ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), ] { assert_eq!(None.apply_to_field(original), original); - assert_eq!(UPPERCASE.apply_to_field(original), upper); + assert_eq!(UpperCase.apply_to_field(original), upper); assert_eq!(PascalCase.apply_to_field(original), pascal); assert_eq!(CamelCase.apply_to_field(original), camel); assert_eq!(SnakeCase.apply_to_field(original), original); diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index 30ede1ce5..da2a0fbdc 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -1,11 +1,13 @@ -use internals::ast::{Container, Data, Field, Style}; -use internals::attr::{Identifier, TagType}; -use internals::{ungroup, Ctxt, Derive}; +use crate::internals::ast::{Container, Data, Field, Style}; +use crate::internals::attr::{Default, Identifier, TagType}; +use crate::internals::{ungroup, Ctxt, Derive}; use syn::{Member, Type}; -/// Cross-cutting checks that require looking at more than a single attrs -/// object. Simpler checks should happen when parsing and building the attrs. +// Cross-cutting checks that require looking at more than a single attrs object. +// Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_default_on_tuple(cx, cont); + check_remote_generic(cx, cont); check_getter(cx, cont); check_flatten(cx, cont); check_identifier(cx, cont); @@ -16,8 +18,63 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_from_and_try_from(cx, cont); } -/// Getters are only allowed inside structs (not enums) with the `remote` -/// attribute. +// If some field of a tuple struct is marked #[serde(default)] then all fields +// after it must also be marked with that attribute, or the struct must have a +// container-level serde(default) attribute. A field's default value is only +// used for tuple fields if the sequence is exhausted at that point; that means +// all subsequent fields will fail to deserialize if they don't have their own +// default. +fn check_default_on_tuple(cx: &Ctxt, cont: &Container) { + if let Default::None = cont.attrs.default() { + if let Data::Struct(Style::Tuple, fields) = &cont.data { + let mut first_default_index = None; + for (i, field) in fields.iter().enumerate() { + // Skipped fields automatically get the #[serde(default)] + // attribute. We are interested only on non-skipped fields here. + if field.attrs.skip_deserializing() { + continue; + } + if let Default::None = field.attrs.default() { + if let Some(first) = first_default_index { + cx.error_spanned_by( + field.ty, + format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first), + ); + } + continue; + } + if first_default_index.is_none() { + first_default_index = Some(i); + } + } + } + } +} + +// Remote derive definition type must have either all of the generics of the +// remote type: +// +// #[serde(remote = "Generic")] +// struct Generic {…} +// +// or none of them, i.e. defining impls for one concrete instantiation of the +// remote type only: +// +// #[serde(remote = "Generic")] +// struct ConcreteDef {…} +// +fn check_remote_generic(cx: &Ctxt, cont: &Container) { + if let Some(remote) = cont.attrs.remote() { + let local_has_generic = !cont.generics.params.is_empty(); + let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); + if local_has_generic && remote_has_generic { + cx.error_spanned_by(remote, "remove generic parameters from this path"); + } + } +} + +// Getters are only allowed inside structs (not enums) with the `remote` +// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { match cont.data { Data::Enum(_) => { @@ -39,7 +96,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) { } } -/// Flattening has some restrictions we can test. +// Flattening has some restrictions we can test. fn check_flatten(cx: &Ctxt, cont: &Container) { match &cont.data { Data::Enum(variants) => { @@ -78,18 +135,16 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { } } -/// The `other` attribute must be used at most once and it must be the last -/// variant of an enum. -/// -/// Inside a `variant_identifier` all variants must be unit variants. Inside a -/// `field_identifier` all but possibly one variant must be unit variants. The -/// last variant may be a newtype variant which is an implicit "other" case. +// The `other` attribute must be used at most once and it must be the last +// variant of an enum. +// +// Inside a `variant_identifier` all variants must be unit variants. Inside a +// `field_identifier` all but possibly one variant must be unit variants. The +// last variant may be a newtype variant which is an implicit "other" case. fn check_identifier(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, - Data::Struct(_, _) => { - return; - } + Data::Struct(_, _) => return, }; for (i, variant) in variants.iter().enumerate() { @@ -166,17 +221,15 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { } } -/// Skip-(de)serializing attributes are not allowed on variants marked -/// (de)serialize_with. +// Skip-(de)serializing attributes are not allowed on variants marked +// (de)serialize_with. fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, - Data::Struct(_, _) => { - return; - } + Data::Struct(_, _) => return, }; - for variant in variants.iter() { + for variant in variants { if variant.attrs.serialize_with().is_some() { if variant.attrs.skip_serializing() { cx.error_spanned_by( @@ -241,10 +294,9 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { } } -/// The tag of an internally-tagged struct variant must not be -/// the same as either one of its fields, as this would result in -/// duplicate keys in the serialized output and/or ambiguity in -/// the to-be-deserialized input. +// The tag of an internally-tagged struct variant must not be the same as either +// one of its fields, as this would result in duplicate keys in the serialized +// output and/or ambiguity in the to-be-deserialized input. fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, @@ -260,25 +312,30 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { cx.error_spanned_by( cont.original, format!("variant field name `{}` conflicts with internal tag", tag), - ) + ); }; for variant in variants { match variant.style { Style::Struct => { + if variant.attrs.untagged() { + continue; + } for field in &variant.fields { - let check_ser = !field.attrs.skip_serializing(); - let check_de = !field.attrs.skip_deserializing(); + let check_ser = + !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); + let check_de = + !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); let name = field.attrs.name(); let ser_name = name.serialize_name(); - if check_ser && ser_name == tag { + if check_ser && ser_name.value == tag { diagnose_conflict(); return; } for de_name in field.attrs.aliases() { - if check_de && de_name == tag { + if check_de && de_name.value == tag { diagnose_conflict(); return; } @@ -290,8 +347,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { } } -/// In the case of adjacently-tagged enums, the type and the -/// contents tag must differ, for the same reason. +// In the case of adjacently-tagged enums, the type and the contents tag must +// differ, for the same reason. fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { let (type_tag, content_tag) = match cont.attrs.tag() { TagType::Adjacent { tag, content } => (tag, content), @@ -309,7 +366,7 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { } } -/// Enums and unit structs cannot be transparent. +// Enums and unit structs cannot be transparent. fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { if !cont.attrs.transparent() { return; @@ -396,7 +453,7 @@ fn member_message(member: &Member) -> String { } fn allow_transparent(field: &Field, derive: Derive) -> bool { - if let Type::Path(ty) = ungroup(&field.ty) { + if let Type::Path(ty) = ungroup(field.ty) { if let Some(seg) = ty.path.segments.last() { if seg.ident == "PhantomData" { return false; diff --git a/serde_derive/src/internals/ctxt.rs b/serde_derive/src/internals/ctxt.rs index d692c2a44..45ec93d7d 100644 --- a/serde_derive/src/internals/ctxt.rs +++ b/serde_derive/src/internals/ctxt.rs @@ -2,7 +2,6 @@ use quote::ToTokens; use std::cell::RefCell; use std::fmt::Display; use std::thread; -use syn; /// A type to collect errors together and format them. /// @@ -44,12 +43,18 @@ impl Ctxt { } /// Consume this object, producing a formatted error string if there are errors. - pub fn check(self) -> Result<(), Vec> { - let errors = self.errors.borrow_mut().take().unwrap(); - match errors.len() { - 0 => Ok(()), - _ => Err(errors), + pub fn check(self) -> syn::Result<()> { + let mut errors = self.errors.borrow_mut().take().unwrap().into_iter(); + + let Some(mut combined) = errors.next() else { + return Ok(()); + }; + + for rest in errors { + combined.combine(rest); } + + Err(combined) } } diff --git a/serde_derive/src/internals/mod.rs b/serde_derive/src/internals/mod.rs index d36b6e45c..cd1e81052 100644 --- a/serde_derive/src/internals/mod.rs +++ b/serde_derive/src/internals/mod.rs @@ -1,15 +1,19 @@ pub mod ast; pub mod attr; - -mod ctxt; -pub use self::ctxt::Ctxt; +pub mod name; mod case; mod check; +mod ctxt; +mod receiver; +mod respan; mod symbol; use syn::Type; +pub use self::ctxt::Ctxt; +pub use self::receiver::replace_receiver; + #[derive(Copy, Clone)] pub enum Derive { Serialize, diff --git a/serde_derive/src/internals/name.rs b/serde_derive/src/internals/name.rs new file mode 100644 index 000000000..4c59f9636 --- /dev/null +++ b/serde_derive/src/internals/name.rs @@ -0,0 +1,113 @@ +use crate::internals::attr::{Attr, VecAttr}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::ToTokens; +use std::cmp::Ordering; +use std::collections::BTreeSet; +use std::fmt::{self, Display}; +use syn::LitStr; + +pub struct MultiName { + pub(crate) serialize: Name, + pub(crate) serialize_renamed: bool, + pub(crate) deserialize: Name, + pub(crate) deserialize_renamed: bool, + pub(crate) deserialize_aliases: BTreeSet, +} + +impl MultiName { + pub(crate) fn from_attrs( + source_name: Name, + ser_name: Attr, + de_name: Attr, + de_aliases: Option>, + ) -> Self { + let mut alias_set = BTreeSet::new(); + if let Some(de_aliases) = de_aliases { + for alias_name in de_aliases.get() { + alias_set.insert(alias_name); + } + } + + let ser_name = ser_name.get(); + let ser_renamed = ser_name.is_some(); + let de_name = de_name.get(); + let de_renamed = de_name.is_some(); + MultiName { + serialize: ser_name.unwrap_or_else(|| source_name.clone()), + serialize_renamed: ser_renamed, + deserialize: de_name.unwrap_or(source_name), + deserialize_renamed: de_renamed, + deserialize_aliases: alias_set, + } + } + + /// Return the container name for the container when serializing. + pub fn serialize_name(&self) -> &Name { + &self.serialize + } + + /// Return the container name for the container when deserializing. + pub fn deserialize_name(&self) -> &Name { + &self.deserialize + } + + pub(crate) fn deserialize_aliases(&self) -> &BTreeSet { + &self.deserialize_aliases + } +} + +#[derive(Clone)] +pub struct Name { + pub value: String, + pub span: Span, +} + +impl ToTokens for Name { + fn to_tokens(&self, tokens: &mut TokenStream) { + LitStr::new(&self.value, self.span).to_tokens(tokens); + } +} + +impl Ord for Name { + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&self.value, &other.value) + } +} + +impl PartialOrd for Name { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Eq for Name {} + +impl PartialEq for Name { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +impl From<&Ident> for Name { + fn from(ident: &Ident) -> Self { + Name { + value: ident.to_string(), + span: ident.span(), + } + } +} + +impl From<&LitStr> for Name { + fn from(lit: &LitStr) -> Self { + Name { + value: lit.value(), + span: lit.span(), + } + } +} + +impl Display for Name { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.value, formatter) + } +} diff --git a/serde_derive/src/internals/receiver.rs b/serde_derive/src/internals/receiver.rs new file mode 100644 index 000000000..a326f667c --- /dev/null +++ b/serde_derive/src/internals/receiver.rs @@ -0,0 +1,293 @@ +use crate::internals::respan::respan; +use proc_macro2::Span; +use quote::ToTokens; +use std::mem; +use syn::{ + parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro, + Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate, +}; + +pub fn replace_receiver(input: &mut DeriveInput) { + let self_ty = { + let ident = &input.ident; + let ty_generics = input.generics.split_for_impl().1; + parse_quote!(#ident #ty_generics) + }; + let mut visitor = ReplaceReceiver(&self_ty); + visitor.visit_generics_mut(&mut input.generics); + visitor.visit_data_mut(&mut input.data); +} + +struct ReplaceReceiver<'a>(&'a TypePath); + +impl ReplaceReceiver<'_> { + fn self_ty(&self, span: Span) -> TypePath { + let tokens = self.0.to_token_stream(); + let respanned = respan(tokens, span); + syn::parse2(respanned).unwrap() + } + + fn self_to_qself(&self, qself: &mut Option, path: &mut Path) { + if path.leading_colon.is_some() || path.segments[0].ident != "Self" { + return; + } + + if path.segments.len() == 1 { + self.self_to_expr_path(path); + return; + } + + let span = path.segments[0].ident.span(); + *qself = Some(QSelf { + lt_token: Token![<](span), + ty: Box::new(Type::Path(self.self_ty(span))), + position: 0, + as_token: None, + gt_token: Token![>](span), + }); + + path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap()); + + let segments = mem::take(&mut path.segments); + path.segments = segments.into_pairs().skip(1).collect(); + } + + fn self_to_expr_path(&self, path: &mut Path) { + let self_ty = self.self_ty(path.segments[0].ident.span()); + let variant = mem::replace(path, self_ty.path); + for segment in &mut path.segments { + if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments { + if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() { + bracketed.colon2_token = Some(::default()); + } + } + } + if variant.segments.len() > 1 { + path.segments.push_punct(::default()); + path.segments.extend(variant.segments.into_pairs().skip(1)); + } + } +} + +impl ReplaceReceiver<'_> { + // `Self` -> `Receiver` + fn visit_type_mut(&mut self, ty: &mut Type) { + let span = if let Type::Path(node) = ty { + if node.qself.is_none() && node.path.is_ident("Self") { + node.path.segments[0].ident.span() + } else { + self.visit_type_path_mut(node); + return; + } + } else { + self.visit_type_mut_impl(ty); + return; + }; + *ty = Type::Path(self.self_ty(span)); + } + + // `Self::Assoc` -> `::Assoc` + fn visit_type_path_mut(&mut self, ty: &mut TypePath) { + if ty.qself.is_none() { + self.self_to_qself(&mut ty.qself, &mut ty.path); + } + self.visit_type_path_mut_impl(ty); + } + + // `Self::method` -> `::method` + fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { + if expr.qself.is_none() { + self.self_to_qself(&mut expr.qself, &mut expr.path); + } + self.visit_expr_path_mut_impl(expr); + } + + // Everything below is simply traversing the syntax tree. + + fn visit_type_mut_impl(&mut self, ty: &mut Type) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Type::Array(ty) => { + self.visit_type_mut(&mut ty.elem); + self.visit_expr_mut(&mut ty.len); + } + Type::BareFn(ty) => { + for arg in &mut ty.inputs { + self.visit_type_mut(&mut arg.ty); + } + self.visit_return_type_mut(&mut ty.output); + } + Type::Group(ty) => self.visit_type_mut(&mut ty.elem), + Type::ImplTrait(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac), + Type::Paren(ty) => self.visit_type_mut(&mut ty.elem), + Type::Path(ty) => { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem), + Type::Reference(ty) => self.visit_type_mut(&mut ty.elem), + Type::Slice(ty) => self.visit_type_mut(&mut ty.elem), + Type::TraitObject(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Tuple(ty) => { + for elem in &mut ty.elems { + self.visit_type_mut(elem); + } + } + + Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {} + + _ => {} + } + } + + fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + + fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) { + if let Some(qself) = &mut expr.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut expr.path); + } + + fn visit_path_mut(&mut self, path: &mut Path) { + for segment in &mut path.segments { + self.visit_path_arguments_mut(&mut segment.arguments); + } + } + + fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) { + match arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(arguments) => { + for arg in &mut arguments.args { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + GenericArgument::Type(arg) => self.visit_type_mut(arg), + GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty), + GenericArgument::Lifetime(_) + | GenericArgument::Const(_) + | GenericArgument::AssocConst(_) + | GenericArgument::Constraint(_) => {} + _ => {} + } + } + } + PathArguments::Parenthesized(arguments) => { + for argument in &mut arguments.inputs { + self.visit_type_mut(argument); + } + self.visit_return_type_mut(&mut arguments.output); + } + } + } + + fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) { + match return_type { + ReturnType::Default => {} + ReturnType::Type(_, output) => self.visit_type_mut(output), + } + } + + fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) { + match bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), + TypeParamBound::Lifetime(_) + | TypeParamBound::PreciseCapture(_) + | TypeParamBound::Verbatim(_) => {} + _ => {} + } + } + + fn visit_generics_mut(&mut self, generics: &mut Generics) { + for param in &mut generics.params { + match param { + GenericParam::Type(param) => { + for bound in &mut param.bounds { + self.visit_type_param_bound_mut(bound); + } + } + GenericParam::Lifetime(_) | GenericParam::Const(_) => {} + } + } + if let Some(where_clause) = &mut generics.where_clause { + for predicate in &mut where_clause.predicates { + match predicate { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + WherePredicate::Type(predicate) => { + self.visit_type_mut(&mut predicate.bounded_ty); + for bound in &mut predicate.bounds { + self.visit_type_param_bound_mut(bound); + } + } + WherePredicate::Lifetime(_) => {} + _ => {} + } + } + } + } + + fn visit_data_mut(&mut self, data: &mut Data) { + match data { + Data::Struct(data) => { + for field in &mut data.fields { + self.visit_type_mut(&mut field.ty); + } + } + Data::Enum(data) => { + for variant in &mut data.variants { + for field in &mut variant.fields { + self.visit_type_mut(&mut field.ty); + } + } + } + Data::Union(_) => {} + } + } + + fn visit_expr_mut(&mut self, expr: &mut Expr) { + match expr { + Expr::Binary(expr) => { + self.visit_expr_mut(&mut expr.left); + self.visit_expr_mut(&mut expr.right); + } + Expr::Call(expr) => { + self.visit_expr_mut(&mut expr.func); + for arg in &mut expr.args { + self.visit_expr_mut(arg); + } + } + Expr::Cast(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_type_mut(&mut expr.ty); + } + Expr::Field(expr) => self.visit_expr_mut(&mut expr.base), + Expr::Index(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_expr_mut(&mut expr.index); + } + Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr), + Expr::Path(expr) => self.visit_expr_path_mut(expr), + Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr), + _ => {} + } + } + + fn visit_macro_mut(&mut self, _mac: &mut Macro) {} +} diff --git a/serde_derive/src/internals/respan.rs b/serde_derive/src/internals/respan.rs new file mode 100644 index 000000000..dcec7017b --- /dev/null +++ b/serde_derive/src/internals/respan.rs @@ -0,0 +1,16 @@ +use proc_macro2::{Group, Span, TokenStream, TokenTree}; + +pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream { + stream + .into_iter() + .map(|token| respan_token(token, span)) + .collect() +} + +fn respan_token(mut token: TokenTree, span: Span) -> TokenTree { + if let TokenTree::Group(g) = &mut token { + *g = Group::new(g.delimiter(), respan(g.stream(), span)); + } + token.set_span(span); + token +} diff --git a/serde_derive/src/internals/symbol.rs b/serde_derive/src/internals/symbol.rs index 318b81bbb..59ef8de7c 100644 --- a/serde_derive/src/internals/symbol.rs +++ b/serde_derive/src/internals/symbol.rs @@ -13,15 +13,19 @@ pub const DEFAULT: Symbol = Symbol("default"); pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields"); pub const DESERIALIZE: Symbol = Symbol("deserialize"); pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with"); +pub const EXPECTING: Symbol = Symbol("expecting"); pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier"); pub const FLATTEN: Symbol = Symbol("flatten"); pub const FROM: Symbol = Symbol("from"); pub const GETTER: Symbol = Symbol("getter"); pub const INTO: Symbol = Symbol("into"); +pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive"); 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 RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields"); +pub const REPR: Symbol = Symbol("repr"); pub const SERDE: Symbol = Symbol("serde"); pub const SERIALIZE: Symbol = Symbol("serialize"); pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with"); @@ -42,7 +46,7 @@ impl PartialEq for Ident { } } -impl<'a> PartialEq for &'a Ident { +impl PartialEq for &Ident { fn eq(&self, word: &Symbol) -> bool { *self == word.0 } @@ -54,7 +58,7 @@ impl PartialEq for Path { } } -impl<'a> PartialEq for &'a Path { +impl PartialEq for &Path { fn eq(&self, word: &Symbol) -> bool { self.is_ident(word.0) } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index 266bc9ded..8577b308e 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -1,7 +1,7 @@ //! This crate provides Serde's two derive macros. //! -//! ```edition2018 -//! # use serde_derive::{Serialize, Deserialize}; +//! ```edition2021 +//! # use serde_derive::{Deserialize, Serialize}; //! # //! #[derive(Serialize, Deserialize)] //! # struct S; @@ -13,14 +13,21 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.118")] -#![allow(unknown_lints, bare_trait_objects)] -#![deny(clippy::all, clippy::pedantic)] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.228")] +#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))] // Ignored clippy lints #![allow( + // clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054 + clippy::branches_sharing_code, clippy::cognitive_complexity, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575 + clippy::collapsible_match, + clippy::derive_partial_eq_without_eq, clippy::enum_variant_names, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797 + clippy::manual_map, clippy::match_like_matches_macro, + clippy::needless_lifetimes, clippy::needless_pass_by_value, clippy::too_many_arguments, clippy::trivially_copy_pass_by_ref, @@ -34,35 +41,43 @@ clippy::cast_possible_truncation, clippy::checked_conversions, clippy::doc_markdown, + clippy::elidable_lifetime_names, clippy::enum_glob_use, - clippy::filter_map, clippy::indexing_slicing, clippy::items_after_statements, + clippy::let_underscore_untyped, + clippy::manual_assert, clippy::map_err_ignore, clippy::match_same_arms, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 + clippy::match_wildcard_for_single_variants, clippy::module_name_repetitions, clippy::must_use_candidate, - clippy::option_if_let_else, clippy::similar_names, clippy::single_match_else, clippy::struct_excessive_bools, clippy::too_many_lines, + clippy::uninlined_format_args, clippy::unseparated_literal_suffix, + clippy::unused_self, clippy::use_self, clippy::wildcard_imports )] +#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] -#[macro_use] +extern crate proc_macro2; extern crate quote; -#[macro_use] extern crate syn; extern crate proc_macro; -extern crate proc_macro2; mod internals; use proc_macro::TokenStream; +use proc_macro2::{Ident, Span}; +use quote::{ToTokens, TokenStreamExt as _}; +use syn::parse_macro_input; use syn::DeriveInput; #[macro_use] @@ -71,28 +86,42 @@ mod bound; mod fragment; mod de; +mod deprecated; mod dummy; mod pretend; mod ser; -mod try; +mod this; + +#[allow(non_camel_case_types)] +struct private; + +impl private { + fn ident(&self) -> Ident { + Ident::new( + concat!("__private", env!("CARGO_PKG_VERSION_PATCH")), + Span::call_site(), + ) + } +} + +impl ToTokens for private { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + tokens.append(self.ident()); + } +} #[proc_macro_derive(Serialize, attributes(serde))] pub fn derive_serialize(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - ser::expand_derive_serialize(&input) - .unwrap_or_else(to_compile_errors) + let mut input = parse_macro_input!(input as DeriveInput); + ser::expand_derive_serialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) .into() } #[proc_macro_derive(Deserialize, attributes(serde))] pub fn derive_deserialize(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - de::expand_derive_deserialize(&input) - .unwrap_or_else(to_compile_errors) + let mut input = parse_macro_input!(input as DeriveInput); + de::expand_derive_deserialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) .into() } - -fn to_compile_errors(errors: Vec) -> proc_macro2::TokenStream { - let compile_errors = errors.iter().map(syn::Error::to_compile_error); - quote!(#(#compile_errors)*) -} diff --git a/serde_derive/src/pretend.rs b/serde_derive/src/pretend.rs index 7233c236a..cfa1a87d1 100644 --- a/serde_derive/src/pretend.rs +++ b/serde_derive/src/pretend.rs @@ -1,7 +1,7 @@ -use proc_macro2::{Span, TokenStream}; -use syn::Ident; - -use internals::ast::{Container, Data, Field, Style}; +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::private; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; // Suppress dead_code warnings that would otherwise appear when using a remote // derive. Other than this pretend code, a struct annotated with remote derive @@ -20,8 +20,8 @@ use internals::ast::{Container, Data, Field, Style}; // 8 | enum EnumDef { V } // | ^ // -pub fn pretend_used(cont: &Container) -> TokenStream { - let pretend_fields = pretend_fields_used(cont); +pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream { + let pretend_fields = pretend_fields_used(cont, is_packed); let pretend_variants = pretend_variants_used(cont); quote! { @@ -32,51 +32,106 @@ pub fn pretend_used(cont: &Container) -> TokenStream { // For structs with named fields, expands to: // +// match None::<&T> { +// Some(T { a: __v0, b: __v1 }) => {} +// _ => {} +// } +// +// For packed structs on sufficiently new rustc, expands to: +// +// match None::<&T> { +// Some(__v @ T { a: _, b: _ }) => { +// let _ = addr_of!(__v.a); +// let _ = addr_of!(__v.b); +// } +// _ => {} +// } +// +// For packed structs on older rustc, we assume Sized and !Drop, and expand to: +// // match None:: { -// Some(T { a: ref __v0, b: ref __v1 }) => {} +// Some(T { a: __v0, b: __v1 }) => {} // _ => {} // } // // For enums, expands to the following but only including struct variants: // -// match None:: { -// Some(T::A { a: ref __v0 }) => {} -// Some(T::B { b: ref __v0 }) => {} +// match None::<&T> { +// Some(T::A { a: __v0 }) => {} +// Some(T::B { b: __v0 }) => {} // _ => {} // } // -// The `ref` is important in case the user has written a Drop impl on their -// type. Rust does not allow destructuring a struct or enum that has a Drop -// impl. -fn pretend_fields_used(cont: &Container) -> TokenStream { +fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream { + match &cont.data { + Data::Enum(variants) => pretend_fields_used_enum(cont, variants), + Data::Struct(Style::Struct | Style::Tuple | Style::Newtype, fields) => { + if is_packed { + pretend_fields_used_struct_packed(cont, fields) + } else { + pretend_fields_used_struct(cont, fields) + } + } + Data::Struct(Style::Unit, _) => quote!(), + } +} + +fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream { let type_ident = &cont.ident; let (_, ty_generics, _) = cont.generics.split_for_impl(); - let patterns = match &cont.data { - Data::Enum(variants) => variants - .iter() - .filter_map(|variant| match variant.style { - Style::Struct => { - let variant_ident = &variant.ident; - let pat = struct_pattern(&variant.fields); - Some(quote!(#type_ident::#variant_ident #pat)) - } - _ => None, - }) - .collect::>(), - Data::Struct(Style::Struct, fields) => { - let pat = struct_pattern(fields); - vec![quote!(#type_ident #pat)] + let members = fields.iter().map(|field| &field.member); + let placeholders = (0usize..).map(|i| format_ident!("__v{}", i)); + + quote! { + match _serde::#private::None::<&#type_ident #ty_generics> { + _serde::#private::Some(#type_ident { #(#members: #placeholders),* }) => {} + _ => {} } - Data::Struct(_, _) => { - return quote!(); + } +} + +fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + + let members = fields.iter().map(|field| &field.member).collect::>(); + + let private2 = private; + quote! { + match _serde::#private::None::<&#type_ident #ty_generics> { + _serde::#private::Some(__v @ #type_ident { #(#members: _),* }) => { + #( + let _ = _serde::#private2::ptr::addr_of!(__v.#members); + )* + } + _ => {} } - }; + } +} + +fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + let patterns = variants + .iter() + .filter_map(|variant| match variant.style { + Style::Struct | Style::Tuple | Style::Newtype => { + let variant_ident = &variant.ident; + let members = variant.fields.iter().map(|field| &field.member); + let placeholders = (0usize..).map(|i| format_ident!("__v{}", i)); + Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* })) + } + Style::Unit => None, + }) + .collect::>(); + + let private2 = private; quote! { - match _serde::export::None::<#type_ident #ty_generics> { + match _serde::#private::None::<&#type_ident #ty_generics> { #( - _serde::export::Some(#patterns) => {} + _serde::#private2::Some(#patterns) => {} )* _ => {} } @@ -107,7 +162,7 @@ fn pretend_variants_used(cont: &Container) -> TokenStream { let cases = variants.iter().map(|variant| { let variant_ident = &variant.ident; let placeholders = &(0..variant.fields.len()) - .map(|i| Ident::new(&format!("__v{}", i), Span::call_site())) + .map(|i| format_ident!("__v{}", i)) .collect::>(); let pat = match variant.style { @@ -120,8 +175,8 @@ fn pretend_variants_used(cont: &Container) -> TokenStream { }; quote! { - match _serde::export::None { - _serde::export::Some((#(#placeholders,)*)) => { + match _serde::#private::None { + _serde::#private::Some((#(#placeholders,)*)) => { let _ = #type_ident::#variant_ident #turbofish #pat; } _ => {} @@ -131,10 +186,3 @@ fn pretend_variants_used(cont: &Container) -> TokenStream { quote!(#(#cases)*) } - -fn struct_pattern(fields: &[Field]) -> TokenStream { - let members = fields.iter().map(|field| &field.member); - let placeholders = - (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); - quote!({ #(#members: ref #placeholders),* }) -} diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index f29d73809..6cec87cf5 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -1,19 +1,20 @@ +use crate::deprecated::allow_deprecated; +use crate::fragment::{Fragment, Match, Stmts}; +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::name::Name; +use crate::internals::{attr, replace_receiver, Ctxt, Derive}; +use crate::{bound, dummy, pretend, private, this}; use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned}; use syn::spanned::Spanned; -use syn::{self, Ident, Index, Member}; +use syn::{parse_quote, Ident, Index, Member}; -use bound; -use dummy; -use fragment::{Fragment, Match, Stmts}; -use internals::ast::{Container, Data, Field, Style, Variant}; -use internals::{attr, Ctxt, Derive}; -use pretend; +pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result { + replace_receiver(input); -pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result> { let ctxt = Ctxt::new(); - let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) { - Some(cont) => cont, - None => return Err(ctxt.check().unwrap_err()), + let Some(cont) = Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident()) else { + return Err(ctxt.check().unwrap_err()); }; precondition(&ctxt, &cont); ctxt.check()?; @@ -22,16 +23,18 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result(__self: &#remote #ty_generics, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error> + #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> where - __S: #serde::Serializer, + __S: _serde::Serializer, { #used #body @@ -41,10 +44,11 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result(&self, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error> + #allow_deprecated + impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> where - __S: #serde::Serializer, + __S: _serde::Serializer, { #body } @@ -54,8 +58,6 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result` for generic parameters for use in + /// expression position. + this_value: syn::Path, /// Generics including any explicit and inferred bounds for the impl. generics: syn::Generics, @@ -101,18 +107,15 @@ impl Parameters { Ident::new("self", Span::call_site()) }; - let this = match cont.attrs.remote() { - Some(remote) => remote.clone(), - None => cont.ident.clone().into(), - }; - + let this_type = this::this_type(cont); + let this_value = this::this_value(cont); let is_packed = cont.attrs.is_packed(); - let generics = build_generics(cont); Parameters { self_var, - this, + this_type, + this_value, generics, is_remote, is_packed, @@ -122,7 +125,7 @@ impl Parameters { /// Type name to use in error messages and `&'static str` arguments to /// various Serializer methods. fn type_name(&self) -> String { - self.this.segments.last().unwrap().ident.to_string() + self.this_type.segments.last().unwrap().ident.to_string() } } @@ -149,7 +152,7 @@ fn build_generics(cont: &Container) -> syn::Generics { } // Fields with a `skip_serializing` or `serialize_with` attribute, or which -// belong to a variant with a 'skip_serializing` or `serialize_with` attribute, +// belong to a variant with a `skip_serializing` or `serialize_with` attribute, // are not serialized by us so we do not generate a bound. Fields with a `bound` // attribute specify their own bound so we do not generate one. All other fields // may need a `T: Serialize` bound where T is the type of the field. @@ -211,7 +214,7 @@ fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { let self_var = ¶ms.self_var; quote_block! { _serde::Serialize::serialize( - &_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)), + &_serde::#private::Into::<#type_into>::into(_serde::#private::Clone::clone(#self_var)), __serializer) } } @@ -283,16 +286,25 @@ fn serialize_tuple_struct( .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)); + let #let_mut __serde_state = _serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)?; #(#serialize_stmts)* _serde::ser::SerializeTupleStruct::end(__serde_state) } } fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { - assert!(fields.len() as u64 <= u64::from(u32::max_value())); + assert!( + fields.len() as u64 <= u64::from(u32::MAX), + "too many fields in {}: {}, maximum supported count is {}", + cattrs.name().serialize_name(), + fields.len(), + u32::MAX, + ); - if cattrs.has_flatten() { + let has_non_skipped_flatten = fields + .iter() + .any(|field| field.attrs.flatten() && !field.attrs.skip_serializing()); + if has_non_skipped_flatten { serialize_struct_as_map(params, fields, cattrs) } else { serialize_struct_as_struct(params, fields, cattrs) @@ -305,7 +317,7 @@ fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTra let type_name = cattrs.name().serialize_name(); let func = struct_trait.serialize_field(Span::call_site()); quote! { - try!(#func(&mut __serde_state, #tag, #type_name)); + #func(&mut __serde_state, #tag, #type_name)?; } } _ => quote! {}, @@ -346,7 +358,7 @@ fn serialize_struct_as_struct( ); quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len)); + let #let_mut __serde_state = _serde::Serializer::serialize_struct(__serializer, #type_name, #len)?; #tag_field #(#serialize_fields)* _serde::ser::SerializeStruct::end(__serde_state) @@ -371,26 +383,8 @@ fn serialize_struct_as_map( let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); - let len = if cattrs.has_flatten() { - quote!(_serde::export::None) - } else { - let len = serialized_fields - .map(|field| match field.attrs.skip_serializing_if() { - None => quote!(1), - Some(path) => { - let field_expr = get_member(params, field, &field.member); - quote!(if #path(#field_expr) { 0 } else { 1 }) - } - }) - .fold( - quote!(#tag_field_exists as usize), - |sum, expr| quote!(#sum + #expr), - ); - quote!(_serde::export::Some(#len)) - }; - quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len)); + let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::#private::None)?; #tag_field #(#serialize_fields)* _serde::ser::SerializeMap::end(__serde_state) @@ -398,11 +392,11 @@ fn serialize_struct_as_map( } fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { - assert!(variants.len() as u64 <= u64::from(u32::max_value())); + assert!(variants.len() as u64 <= u64::from(u32::MAX)); let self_var = ¶ms.self_var; - let arms: Vec<_> = variants + let mut arms: Vec<_> = variants .iter() .enumerate() .map(|(variant_index, variant)| { @@ -410,6 +404,12 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont }) .collect(); + if cattrs.remote().is_some() && cattrs.non_exhaustive() { + arms.push(quote! { + ref unrecognized => _serde::#private::Err(_serde::ser::Error::custom(_serde::#private::ser::CannotSerializeVariant(unrecognized))), + }); + } + quote_expr! { match *#self_var { #(#arms)* @@ -423,7 +423,7 @@ fn serialize_variant( variant_index: u32, cattrs: &attr::Container, ) -> TokenStream { - let this = ¶ms.this; + let this_value = ¶ms.this_value; let variant_ident = &variant.ident; if variant.attrs.skip_serializing() { @@ -433,7 +433,7 @@ fn serialize_variant( variant_ident ); let skipped_err = quote! { - _serde::export::Err(_serde::ser::Error::custom(#skipped_msg)) + _serde::#private::Err(_serde::ser::Error::custom(#skipped_msg)) }; let fields_pat = match variant.style { Style::Unit => quote!(), @@ -441,47 +441,56 @@ fn serialize_variant( Style::Struct => quote!({ .. }), }; quote! { - #this::#variant_ident #fields_pat => #skipped_err, + #this_value::#variant_ident #fields_pat => #skipped_err, } } else { // variant wasn't skipped let case = match variant.style { Style::Unit => { quote! { - #this::#variant_ident + #this_value::#variant_ident } } Style::Newtype => { quote! { - #this::#variant_ident(ref __field0) + #this_value::#variant_ident(ref __field0) } } Style::Tuple => { let field_names = (0..variant.fields.len()) .map(|i| Ident::new(&format!("__field{}", i), Span::call_site())); quote! { - #this::#variant_ident(#(ref #field_names),*) + #this_value::#variant_ident(#(ref #field_names),*) } } Style::Struct => { let members = variant.fields.iter().map(|f| &f.member); quote! { - #this::#variant_ident { #(ref #members),* } + #this_value::#variant_ident { #(ref #members),* } } } }; - let body = Match(match cattrs.tag() { - attr::TagType::External => { + let body = Match(match (cattrs.tag(), variant.attrs.untagged()) { + (attr::TagType::External, false) => { serialize_externally_tagged_variant(params, variant, variant_index, cattrs) } - attr::TagType::Internal { tag } => { + (attr::TagType::Internal { tag }, false) => { serialize_internally_tagged_variant(params, variant, cattrs, tag) } - attr::TagType::Adjacent { tag, content } => { - serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content) + (attr::TagType::Adjacent { tag, content }, false) => { + serialize_adjacently_tagged_variant( + params, + variant, + cattrs, + variant_index, + tag, + content, + ) + } + (attr::TagType::None, _) | (_, true) => { + serialize_untagged_variant(params, variant, cattrs) } - attr::TagType::None => serialize_untagged_variant(params, variant, cattrs), }); quote! { @@ -558,7 +567,7 @@ fn serialize_externally_tagged_variant( }, params, &variant.fields, - &type_name, + type_name, ), } } @@ -578,7 +587,7 @@ fn serialize_internally_tagged_variant( if let Some(path) = variant.attrs.serialize_with() { let ser = wrap_serialize_variant_with(params, path, variant); return quote_expr! { - _serde::private::ser::serialize_tagged_newtype( + _serde::#private::ser::serialize_tagged_newtype( __serializer, #enum_ident_str, #variant_ident_str, @@ -592,10 +601,10 @@ fn serialize_internally_tagged_variant( match effective_style(variant) { Style::Unit => { quote_block! { - let mut __struct = try!(_serde::Serializer::serialize_struct( - __serializer, #type_name, 1)); - try!(_serde::ser::SerializeStruct::serialize_field( - &mut __struct, #tag, #variant_name)); + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 1)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)?; _serde::ser::SerializeStruct::end(__struct) } } @@ -607,7 +616,7 @@ fn serialize_internally_tagged_variant( } let span = field.original.span(); - let func = quote_spanned!(span=> _serde::private::ser::serialize_tagged_newtype); + let func = quote_spanned!(span=> _serde::#private::ser::serialize_tagged_newtype); quote_expr! { #func( __serializer, @@ -623,7 +632,7 @@ fn serialize_internally_tagged_variant( StructVariant::InternallyTagged { tag, variant_name }, params, &variant.fields, - &type_name, + type_name, ), Style::Tuple => unreachable!("checked in serde_derive_internals"), } @@ -633,12 +642,20 @@ fn serialize_adjacently_tagged_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, + variant_index: u32, tag: &str, content: &str, ) -> Fragment { - let this = ¶ms.this; + let this_type = ¶ms.this_type; let type_name = cattrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name(); + let serialize_variant = quote! { + &_serde::#private::ser::AdjacentlyTaggedEnumVariant { + enum_name: #type_name, + variant_index: #variant_index, + variant_name: #variant_name, + } + }; let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() { let ser = wrap_serialize_variant_with(params, path, variant); @@ -649,10 +666,10 @@ fn serialize_adjacently_tagged_variant( match effective_style(variant) { Style::Unit => { return quote_block! { - let mut __struct = try!(_serde::Serializer::serialize_struct( - __serializer, #type_name, 1)); - try!(_serde::ser::SerializeStruct::serialize_field( - &mut __struct, #tag, #variant_name)); + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 1)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; _serde::ser::SerializeStruct::end(__struct) }; } @@ -666,12 +683,12 @@ fn serialize_adjacently_tagged_variant( let span = field.original.span(); let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); return quote_block! { - let mut __struct = try!(_serde::Serializer::serialize_struct( - __serializer, #type_name, 2)); - try!(_serde::ser::SerializeStruct::serialize_field( - &mut __struct, #tag, #variant_name)); - try!(#func( - &mut __struct, #content, #field_expr)); + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 2)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; + #func( + &mut __struct, #content, #field_expr)?; _serde::ser::SerializeStruct::end(__struct) }; } @@ -682,13 +699,13 @@ fn serialize_adjacently_tagged_variant( StructVariant::Untagged, params, &variant.fields, - &variant_name, + variant_name, ), } }); let fields_ty = variant.fields.iter().map(|f| &f.ty); - let fields_ident: &Vec<_> = &match variant.style { + let fields_ident: &[_] = &match variant.style { Style::Unit => { if variant.attrs.serialize_with().is_some() { vec![] @@ -713,13 +730,15 @@ fn serialize_adjacently_tagged_variant( let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); quote_block! { + #[doc(hidden)] struct __AdjacentlyTagged #wrapper_generics #where_clause { data: (#(&'__a #fields_ty,)*), - phantom: _serde::export::PhantomData<#this #ty_generics>, + phantom: _serde::#private::PhantomData<#this_type #ty_generics>, } + #[automatically_derived] impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> where __S: _serde::Serializer, { @@ -730,15 +749,15 @@ fn serialize_adjacently_tagged_variant( } } - let mut __struct = try!(_serde::Serializer::serialize_struct( - __serializer, #type_name, 2)); - try!(_serde::ser::SerializeStruct::serialize_field( - &mut __struct, #tag, #variant_name)); - try!(_serde::ser::SerializeStruct::serialize_field( + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 2)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; + _serde::ser::SerializeStruct::serialize_field( &mut __struct, #content, &__AdjacentlyTagged { data: (#(#fields_ident,)*), - phantom: _serde::export::PhantomData::<#this #ty_generics>, - })); + phantom: _serde::#private::PhantomData::<#this_type #ty_generics>, + })?; _serde::ser::SerializeStruct::end(__struct) } } @@ -777,16 +796,16 @@ fn serialize_untagged_variant( Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), Style::Struct => { let type_name = cattrs.name().serialize_name(); - serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, &type_name) + serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, type_name) } } } -enum TupleVariant { +enum TupleVariant<'a> { ExternallyTagged { - type_name: String, + type_name: &'a Name, variant_index: u32, - variant_name: String, + variant_name: &'a Name, }, Untagged, } @@ -828,21 +847,21 @@ fn serialize_tuple_variant( variant_name, } => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant( + let #let_mut __serde_state = _serde::Serializer::serialize_tuple_variant( __serializer, #type_name, #variant_index, #variant_name, - #len)); + #len)?; #(#serialize_stmts)* _serde::ser::SerializeTupleVariant::end(__serde_state) } } TupleVariant::Untagged => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple( + let #let_mut __serde_state = _serde::Serializer::serialize_tuple( __serializer, - #len)); + #len)?; #(#serialize_stmts)* _serde::ser::SerializeTuple::end(__serde_state) } @@ -853,20 +872,20 @@ fn serialize_tuple_variant( enum StructVariant<'a> { ExternallyTagged { variant_index: u32, - variant_name: String, + variant_name: &'a Name, }, InternallyTagged { tag: &'a str, - variant_name: String, + variant_name: &'a Name, }, Untagged, } -fn serialize_struct_variant<'a>( - context: StructVariant<'a>, +fn serialize_struct_variant( + context: StructVariant, params: &Parameters, fields: &[Field], - name: &str, + name: &Name, ) -> Fragment { if fields.iter().any(|field| field.attrs.flatten()) { return serialize_struct_variant_with_flatten(context, params, fields, name); @@ -905,40 +924,40 @@ fn serialize_struct_variant<'a>( variant_name, } => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant( + let #let_mut __serde_state = _serde::Serializer::serialize_struct_variant( __serializer, #name, #variant_index, #variant_name, #len, - )); + )?; #(#serialize_fields)* _serde::ser::SerializeStructVariant::end(__serde_state) } } StructVariant::InternallyTagged { tag, variant_name } => { quote_block! { - let mut __serde_state = try!(_serde::Serializer::serialize_struct( + let mut __serde_state = _serde::Serializer::serialize_struct( __serializer, #name, #len + 1, - )); - try!(_serde::ser::SerializeStruct::serialize_field( + )?; + _serde::ser::SerializeStruct::serialize_field( &mut __serde_state, #tag, #variant_name, - )); + )?; #(#serialize_fields)* _serde::ser::SerializeStruct::end(__serde_state) } } StructVariant::Untagged => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct( + let #let_mut __serde_state = _serde::Serializer::serialize_struct( __serializer, #name, #len, - )); + )?; #(#serialize_fields)* _serde::ser::SerializeStruct::end(__serde_state) } @@ -946,11 +965,11 @@ fn serialize_struct_variant<'a>( } } -fn serialize_struct_variant_with_flatten<'a>( - context: StructVariant<'a>, +fn serialize_struct_variant_with_flatten( + context: StructVariant, params: &Parameters, fields: &[Field], - name: &str, + name: &Name, ) -> Fragment { let struct_trait = StructTrait::SerializeMap; let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); @@ -967,7 +986,7 @@ fn serialize_struct_variant_with_flatten<'a>( variant_index, variant_name, } => { - let this = ¶ms.this; + let this_type = ¶ms.this_type; let fields_ty = fields.iter().map(|f| &f.ty); let members = &fields.iter().map(|f| &f.member).collect::>(); @@ -976,20 +995,22 @@ fn serialize_struct_variant_with_flatten<'a>( let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); quote_block! { + #[doc(hidden)] struct __EnumFlatten #wrapper_generics #where_clause { data: (#(&'__a #fields_ty,)*), - phantom: _serde::export::PhantomData<#this #ty_generics>, + phantom: _serde::#private::PhantomData<#this_type #ty_generics>, } + #[automatically_derived] impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> where __S: _serde::Serializer, { let (#(#members,)*) = self.data; - let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + let #let_mut __serde_state = _serde::Serializer::serialize_map( __serializer, - _serde::export::None)); + _serde::#private::None)?; #(#serialize_fields)* _serde::ser::SerializeMap::end(__serde_state) } @@ -1002,29 +1023,29 @@ fn serialize_struct_variant_with_flatten<'a>( #variant_name, &__EnumFlatten { data: (#(#members,)*), - phantom: _serde::export::PhantomData::<#this #ty_generics>, + phantom: _serde::#private::PhantomData::<#this_type #ty_generics>, }) } } StructVariant::InternallyTagged { tag, variant_name } => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + let #let_mut __serde_state = _serde::Serializer::serialize_map( __serializer, - _serde::export::None)); - try!(_serde::ser::SerializeMap::serialize_entry( + _serde::#private::None)?; + _serde::ser::SerializeMap::serialize_entry( &mut __serde_state, #tag, #variant_name, - )); + )?; #(#serialize_fields)* _serde::ser::SerializeMap::end(__serde_state) } } StructVariant::Untagged => { quote_block! { - let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + let #let_mut __serde_state = _serde::Serializer::serialize_map( __serializer, - _serde::export::None)); + _serde::#private::None)?; #(#serialize_fields)* _serde::ser::SerializeMap::end(__serde_state) } @@ -1069,7 +1090,7 @@ fn serialize_tuple_struct_visitor( let span = field.original.span(); let func = tuple_trait.serialize_element(span); let ser = quote! { - try!(#func(&mut __serde_state, #field_expr)); + #func(&mut __serde_state, #field_expr)?; }; match skip { @@ -1095,7 +1116,7 @@ fn serialize_struct_visitor( let mut field_expr = if is_enum { quote!(#member) } else { - get_member(params, field, &member) + get_member(params, field, member) }; let key_expr = field.attrs.name().serialize_name(); @@ -1113,12 +1134,12 @@ fn serialize_struct_visitor( let ser = if field.attrs.flatten() { let func = quote_spanned!(span=> _serde::Serialize::serialize); quote! { - try!(#func(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state))); + #func(&#field_expr, _serde::#private::ser::FlatMapSerializer(&mut __serde_state))?; } } else { let func = struct_trait.serialize_field(span); quote! { - try!(#func(&mut __serde_state, #key_expr, #field_expr)); + #func(&mut __serde_state, #key_expr, #field_expr)?; } }; @@ -1130,7 +1151,7 @@ fn serialize_struct_visitor( if !#skip { #ser } else { - try!(#skip_func(&mut __serde_state, #key_expr)); + #skip_func(&mut __serde_state, #key_expr)?; } } } else { @@ -1188,7 +1209,7 @@ fn wrap_serialize_with( field_tys: &[&syn::Type], field_exprs: &[TokenStream], ) -> TokenStream { - let this = ¶ms.this; + let this_type = ¶ms.this_type; let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let wrapper_generics = if field_exprs.is_empty() { @@ -1205,31 +1226,44 @@ fn wrap_serialize_with( }) }); - quote!({ + let self_var = quote!(self); + let serializer_var = quote!(__s); + + // If #serialize_with returns wrong type, error will be reported on here. + // We attach span of the path to this piece so error will be reported + // on the #[serde(with = "...")] + // ^^^^^ + let wrapper_serialize = quote_spanned! {serialize_with.span()=> + #serialize_with(#(#self_var.values.#field_access, )* #serializer_var) + }; + + quote!(&{ + #[doc(hidden)] struct __SerializeWith #wrapper_impl_generics #where_clause { values: (#(&'__a #field_tys, )*), - phantom: _serde::export::PhantomData<#this #ty_generics>, + phantom: _serde::#private::PhantomData<#this_type #ty_generics>, } + #[automatically_derived] impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { - fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error> + fn serialize<__S>(&#self_var, #serializer_var: __S) -> _serde::#private::Result<__S::Ok, __S::Error> where __S: _serde::Serializer, { - #serialize_with(#(self.values.#field_access, )* __s) + #wrapper_serialize } } - &__SerializeWith { + __SerializeWith { values: (#(#field_exprs, )*), - phantom: _serde::export::PhantomData::<#this #ty_generics>, + phantom: _serde::#private::PhantomData::<#this_type #ty_generics>, } }) } // Serialization of an empty struct results in code like: // -// let mut __serde_state = try!(serializer.serialize_struct("S", 0)); +// let mut __serde_state = serializer.serialize_struct("S", 0)?; // _serde::ser::SerializeStruct::end(__serde_state) // // where we want to omit the `mut` to avoid a warning. @@ -1258,11 +1292,11 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea quote!(&#self_var.#member) }; let ty = field.ty; - quote!(_serde::private::ser::constrain::<#ty>(#inner)) + quote!(_serde::#private::ser::constrain::<#ty>(#inner)) } (true, Some(getter)) => { let ty = field.ty; - quote!(_serde::private::ser::constrain::<#ty>(&#getter(#self_var))) + quote!(_serde::#private::ser::constrain::<#ty>(&#getter(#self_var))) } (false, Some(_)) => { unreachable!("getter is only allowed for remote impls"); diff --git a/serde_derive/src/this.rs b/serde_derive/src/this.rs new file mode 100644 index 000000000..941cea40c --- /dev/null +++ b/serde_derive/src/this.rs @@ -0,0 +1,32 @@ +use crate::internals::ast::Container; +use syn::{Path, PathArguments, Token}; + +pub fn this_type(cont: &Container) -> Path { + if let Some(remote) = cont.attrs.remote() { + let mut this = remote.clone(); + for segment in &mut this.segments { + if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments { + arguments.colon2_token = None; + } + } + this + } else { + Path::from(cont.ident.clone()) + } +} + +pub fn this_value(cont: &Container) -> Path { + if let Some(remote) = cont.attrs.remote() { + let mut this = remote.clone(); + for segment in &mut this.segments { + if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments { + if arguments.colon2_token.is_none() { + arguments.colon2_token = Some(Token![::](arguments.lt_token.span)); + } + } + } + this + } else { + Path::from(cont.ident.clone()) + } +} diff --git a/serde_derive/src/try.rs b/serde_derive/src/try.rs deleted file mode 100644 index 48829b635..000000000 --- a/serde_derive/src/try.rs +++ /dev/null @@ -1,24 +0,0 @@ -use proc_macro2::{Punct, Spacing, TokenStream}; - -// None of our generated code requires the `From::from` error conversion -// performed by the standard library's `try!` macro. With this simplified macro -// we see a significant improvement in type checking and borrow checking time of -// the generated code and a slight improvement in binary size. -pub fn replacement() -> TokenStream { - // Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it. - let dollar = Punct::new('$', Spacing::Alone); - - quote! { - #[allow(unused_macros)] - macro_rules! try { - (#dollar __expr:expr) => { - match #dollar __expr { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - } - } -} diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index 64ee1c629..97f391c78 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -1,22 +1,32 @@ [package] name = "serde_derive_internals" -version = "0.25.0" # remember to update html_root_url +version = "0.29.1" authors = ["Erick Tryzelaar ", "David Tolnay "] -license = "MIT OR Apache-2.0" description = "AST representation used by Serde derive macros. Unstable." -homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" documentation = "https://docs.rs/serde_derive_internals" +edition = "2021" +exclude = ["build.rs"] +homepage = "https://serde.rs" keywords = ["serde", "serialization"] -include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.68" [lib] path = "lib.rs" [dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "1.0.33", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", + "--extern-html-root-url=proc_macro=https://doc.rust-lang.org", +] diff --git a/serde_derive_internals/build.rs b/serde_derive_internals/build.rs new file mode 100644 index 000000000..b2bbb3a56 --- /dev/null +++ b/serde_derive_internals/build.rs @@ -0,0 +1,23 @@ +use std::path::Path; + +fn main() { + // Warning: build.rs is not published to crates.io. + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=src/mod.rs"); + + println!("cargo:rustc-cfg=check_cfg"); + println!("cargo:rustc-check-cfg=cfg(check_cfg)"); + println!("cargo:rustc-check-cfg=cfg(exhaustive)"); + println!("cargo:rustc-check-cfg=cfg(serde_build_from_git)"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"deserialize_in_place\"))"); + + // Sometimes on Windows the git checkout does not correctly wire up the + // symlink from serde_derive_internals/src to serde_derive/src/internals. + // When this happens we'll just build based on relative paths within the git + // repo. + let mod_behind_symlink = Path::new("src/mod.rs"); + if !mod_behind_symlink.exists() { + println!("cargo:rustc-cfg=serde_build_from_git"); + } +} diff --git a/serde_derive_internals/lib.rs b/serde_derive_internals/lib.rs index 5bc767569..73680082b 100644 --- a/serde_derive_internals/lib.rs +++ b/serde_derive_internals/lib.rs @@ -1,26 +1,54 @@ -#![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( - cognitive_complexity, - redundant_field_names, - result_unit_err, - trivially_copy_pass_by_ref, - wildcard_in_or_patterns, - // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 - unnested_or_patterns, - ) +#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.29.1")] +#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))] +// Ignored clippy lints +#![allow( + clippy::cognitive_complexity, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575 + clippy::collapsible_match, + clippy::derive_partial_eq_without_eq, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797 + clippy::manual_map, + clippy::missing_panics_doc, + clippy::needless_lifetimes, + clippy::redundant_field_names, + clippy::result_unit_err, + clippy::should_implement_trait, + clippy::trivially_copy_pass_by_ref, + clippy::wildcard_in_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, )] - -#[macro_use] -extern crate syn; +// Ignored clippy_pedantic lints +#![allow( + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::enum_glob_use, + clippy::items_after_statements, + clippy::let_underscore_untyped, + clippy::manual_assert, + clippy::match_same_arms, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 + clippy::match_wildcard_for_single_variants, + clippy::missing_errors_doc, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::return_self_not_must_use, + clippy::similar_names, + clippy::single_match_else, + clippy::struct_excessive_bools, + clippy::too_many_lines, + clippy::uninlined_format_args, + clippy::unused_self, + clippy::wildcard_imports +)] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] extern crate proc_macro2; extern crate quote; +extern crate syn; -#[path = "src/mod.rs"] +#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")] +#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")] mod internals; pub use internals::*; diff --git a/serde_test/Cargo.toml b/serde_test/Cargo.toml deleted file mode 100644 index 84c2fb889..000000000 --- a/serde_test/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "serde_test" -version = "1.0.118" # remember to update html_root_url -authors = ["Erick Tryzelaar ", "David Tolnay "] -license = "MIT OR Apache-2.0" -description = "Token De/Serializer for testing De/Serialize implementations" -homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" -documentation = "https://docs.serde.rs/serde_test/" -keywords = ["serde", "serialization"] -readme = "crates-io.md" -include = ["src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] - -[dependencies] -serde = { version = "1.0.60", path = "../serde" } - -[dev-dependencies] -serde = { version = "1.0", path = "../serde" } -serde_derive = { version = "1.0", path = "../serde_derive" } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/serde_test/README.md b/serde_test/README.md deleted file mode 120000 index 32d46ee88..000000000 --- a/serde_test/README.md +++ /dev/null @@ -1 +0,0 @@ -../README.md \ No newline at end of file diff --git a/serde_test/crates-io.md b/serde_test/crates-io.md deleted file mode 120000 index ae66dc9c4..000000000 --- a/serde_test/crates-io.md +++ /dev/null @@ -1 +0,0 @@ -../crates-io.md \ No newline at end of file diff --git a/serde_test/src/assert.rs b/serde_test/src/assert.rs deleted file mode 100644 index 3ab9d035c..000000000 --- a/serde_test/src/assert.rs +++ /dev/null @@ -1,218 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use de::Deserializer; -use ser::Serializer; -use token::Token; - -use std::fmt::Debug; - -/// Runs both `assert_ser_tokens` and `assert_de_tokens`. -/// -/// ```edition2018 -/// # use serde::{Serialize, Deserialize}; -/// # use serde_test::{assert_tokens, Token}; -/// # -/// #[derive(Serialize, Deserialize, PartialEq, Debug)] -/// struct S { -/// a: u8, -/// b: u8, -/// } -/// -/// let s = S { a: 0, b: 0 }; -/// assert_tokens(&s, &[ -/// Token::Struct { name: "S", len: 2 }, -/// Token::Str("a"), -/// Token::U8(0), -/// Token::Str("b"), -/// Token::U8(0), -/// Token::StructEnd, -/// ]); -/// ``` -pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token]) -where - T: Serialize + Deserialize<'de> + PartialEq + Debug, -{ - assert_ser_tokens(value, tokens); - assert_de_tokens(value, tokens); -} - -/// Asserts that `value` serializes to the given `tokens`. -/// -/// ```edition2018 -/// # use serde::{Serialize, Deserialize}; -/// # use serde_test::{assert_ser_tokens, Token}; -/// # -/// #[derive(Serialize, Deserialize, PartialEq, Debug)] -/// struct S { -/// a: u8, -/// b: u8, -/// } -/// -/// let s = S { a: 0, b: 0 }; -/// assert_ser_tokens(&s, &[ -/// Token::Struct { name: "S", len: 2 }, -/// Token::Str("a"), -/// Token::U8(0), -/// Token::Str("b"), -/// Token::U8(0), -/// Token::StructEnd, -/// ]); -/// ``` -pub fn assert_ser_tokens(value: &T, tokens: &[Token]) -where - T: Serialize, -{ - let mut ser = Serializer::new(tokens); - match value.serialize(&mut ser) { - Ok(_) => {} - Err(err) => panic!("value failed to serialize: {}", err), - } - - if ser.remaining() > 0 { - panic!("{} remaining tokens", ser.remaining()); - } -} - -/// Asserts that `value` serializes to the given `tokens`, and then yields -/// `error`. -/// -/// ```edition2018 -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// -/// use serde::Serialize; -/// use serde_test::{assert_ser_tokens_error, Token}; -/// -/// #[derive(Serialize)] -/// struct Example { -/// lock: Arc>, -/// } -/// -/// fn main() { -/// let example = Example { lock: Arc::new(Mutex::new(0)) }; -/// let lock = example.lock.clone(); -/// -/// let _ = thread::spawn(move || { -/// // This thread will acquire the mutex first, unwrapping the result -/// // of `lock` because the lock has not been poisoned. -/// let _guard = lock.lock().unwrap(); -/// -/// // This panic while holding the lock (`_guard` is in scope) will -/// // poison the mutex. -/// panic!() -/// }).join(); -/// -/// let expected = &[ -/// Token::Struct { name: "Example", len: 1 }, -/// Token::Str("lock"), -/// ]; -/// let error = "lock poison error while serializing"; -/// assert_ser_tokens_error(&example, expected, error); -/// } -/// ``` -pub fn assert_ser_tokens_error(value: &T, tokens: &[Token], error: &str) -where - T: Serialize, -{ - let mut ser = Serializer::new(tokens); - match value.serialize(&mut ser) { - Ok(_) => panic!("value serialized successfully"), - Err(e) => assert_eq!(e, *error), - } - - if ser.remaining() > 0 { - panic!("{} remaining tokens", ser.remaining()); - } -} - -/// Asserts that the given `tokens` deserialize into `value`. -/// -/// ```edition2018 -/// # use serde::{Serialize, Deserialize}; -/// # use serde_test::{assert_de_tokens, Token}; -/// # -/// #[derive(Serialize, Deserialize, PartialEq, Debug)] -/// struct S { -/// a: u8, -/// b: u8, -/// } -/// -/// let s = S { a: 0, b: 0 }; -/// assert_de_tokens(&s, &[ -/// Token::Struct { name: "S", len: 2 }, -/// Token::Str("a"), -/// Token::U8(0), -/// Token::Str("b"), -/// Token::U8(0), -/// Token::StructEnd, -/// ]); -/// ``` -pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) -where - T: Deserialize<'de> + PartialEq + Debug, -{ - let mut de = Deserializer::new(tokens); - let mut deserialized_val = match T::deserialize(&mut de) { - Ok(v) => { - assert_eq!(v, *value); - v - } - Err(e) => panic!("tokens failed to deserialize: {}", e), - }; - if de.remaining() > 0 { - panic!("{} remaining tokens", de.remaining()); - } - - // Do the same thing for deserialize_in_place. This isn't *great* because a - // no-op impl of deserialize_in_place can technically succeed here. Still, - // this should catch a lot of junk. - let mut de = Deserializer::new(tokens); - match T::deserialize_in_place(&mut de, &mut deserialized_val) { - Ok(()) => { - assert_eq!(deserialized_val, *value); - } - Err(e) => panic!("tokens failed to deserialize_in_place: {}", e), - } - if de.remaining() > 0 { - panic!("{} remaining tokens", de.remaining()); - } -} - -/// Asserts that the given `tokens` yield `error` when deserializing. -/// -/// ```edition2018 -/// # use serde::{Serialize, Deserialize}; -/// # use serde_test::{assert_de_tokens_error, Token}; -/// # -/// #[derive(Serialize, Deserialize, PartialEq, Debug)] -/// #[serde(deny_unknown_fields)] -/// struct S { -/// a: u8, -/// b: u8, -/// } -/// -/// assert_de_tokens_error::( -/// &[ -/// Token::Struct { name: "S", len: 2 }, -/// Token::Str("x"), -/// ], -/// "unknown field `x`, expected `a` or `b`", -/// ); -/// ``` -pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str) -where - T: Deserialize<'de>, -{ - let mut de = Deserializer::new(tokens); - match T::deserialize(&mut de) { - Ok(_) => panic!("tokens deserialized successfully"), - Err(e) => assert_eq!(e, *error), - } - - // There may be one token left if a peek caused the error - de.next_token_opt(); - - if de.remaining() > 0 { - panic!("{} remaining tokens", de.remaining()); - } -} diff --git a/serde_test/src/configure.rs b/serde_test/src/configure.rs deleted file mode 100644 index fb962c39c..000000000 --- a/serde_test/src/configure.rs +++ /dev/null @@ -1,836 +0,0 @@ -use std::fmt; - -use serde::ser::{ - SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, - SerializeTupleStruct, SerializeTupleVariant, -}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Readable(T); -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Compact(T); - -/// Trait to determine whether a value is represented in human-readable or -/// compact form. -/// -/// ```edition2018 -/// use serde::{Deserialize, Deserializer, Serialize, Serializer}; -/// use serde_test::{assert_tokens, Configure, Token}; -/// -/// #[derive(Debug, PartialEq)] -/// struct Example(u8, u8); -/// -/// impl Serialize for Example { -/// fn serialize(&self, serializer: S) -> Result -/// where -/// S: Serializer, -/// { -/// if serializer.is_human_readable() { -/// format!("{}.{}", self.0, self.1).serialize(serializer) -/// } else { -/// (self.0, self.1).serialize(serializer) -/// } -/// } -/// } -/// -/// impl<'de> Deserialize<'de> for Example { -/// fn deserialize(deserializer: D) -> Result -/// where -/// D: Deserializer<'de>, -/// { -/// use serde::de::Error; -/// if deserializer.is_human_readable() { -/// let s = String::deserialize(deserializer)?; -/// let parts: Vec<_> = s.split('.').collect(); -/// Ok(Example( -/// parts[0].parse().map_err(D::Error::custom)?, -/// parts[1].parse().map_err(D::Error::custom)?, -/// )) -/// } else { -/// let (x, y) = Deserialize::deserialize(deserializer)?; -/// Ok(Example(x, y)) -/// } -/// } -/// } -/// -/// fn main() { -/// assert_tokens( -/// &Example(1, 0).compact(), -/// &[ -/// Token::Tuple { len: 2 }, -/// Token::U8(1), -/// Token::U8(0), -/// Token::TupleEnd, -/// ], -/// ); -/// assert_tokens(&Example(1, 0).readable(), &[Token::Str("1.0")]); -/// } -/// ``` -pub trait Configure { - /// Marks `self` as using `is_human_readable == true` - fn readable(self) -> Readable - where - Self: Sized, - { - Readable(self) - } - /// Marks `self` as using `is_human_readable == false` - fn compact(self) -> Compact - where - Self: Sized, - { - Compact(self) - } -} - -impl Configure for T {} - -impl Serialize for Readable -where - T: Serialize, -{ - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0.serialize(Readable(serializer)) - } -} -impl Serialize for Compact -where - T: Serialize, -{ - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0.serialize(Compact(serializer)) - } -} -impl<'de, T> Deserialize<'de> for Readable -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - T::deserialize(Readable(deserializer)).map(Readable) - } -} -impl<'de, T> Deserialize<'de> for Compact -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - T::deserialize(Compact(deserializer)).map(Compact) - } -} - -impl<'de, T> DeserializeSeed<'de> for Readable -where - T: DeserializeSeed<'de>, -{ - type Value = T::Value; - - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - self.0.deserialize(Readable(deserializer)) - } -} -impl<'de, T> DeserializeSeed<'de> for Compact -where - T: DeserializeSeed<'de>, -{ - type Value = T::Value; - - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - self.0.deserialize(Compact(deserializer)) - } -} - -macro_rules! forward_method { - ($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => { - fn $name (self $(, $arg : $arg_type)* ) -> $return_type { - (self.0).$name( $($arg),* ) - } - }; -} - -macro_rules! forward_serialize_methods { - ( $( $name: ident $arg_type: ty ),* ) => { - $( - forward_method!($name(self, v : $arg_type) -> Result); - )* - }; -} - -macro_rules! impl_serializer { - ($wrapper:ident, $is_human_readable:expr) => { - impl Serializer for $wrapper - where - S: Serializer, - { - type Ok = S::Ok; - type Error = S::Error; - - type SerializeSeq = $wrapper; - type SerializeTuple = $wrapper; - type SerializeTupleStruct = $wrapper; - type SerializeTupleVariant = $wrapper; - type SerializeMap = $wrapper; - type SerializeStruct = $wrapper; - type SerializeStructVariant = $wrapper; - - fn is_human_readable(&self) -> bool { - $is_human_readable - } - - forward_serialize_methods! { - serialize_bool bool, - serialize_i8 i8, - serialize_i16 i16, - serialize_i32 i32, - serialize_i64 i64, - serialize_u8 u8, - serialize_u16 u16, - serialize_u32 u32, - serialize_u64 u64, - serialize_f32 f32, - serialize_f64 f64, - serialize_char char, - serialize_str &str, - serialize_bytes &[u8], - serialize_unit_struct &'static str - - } - - fn serialize_unit(self) -> Result { - self.0.serialize_unit() - } - - fn serialize_unit_variant( - self, - name: &'static str, - variant_index: u32, - variant: &'static str, - ) -> Result { - self.0.serialize_unit_variant(name, variant_index, variant) - } - - fn serialize_newtype_struct( - self, - name: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - self.0.serialize_newtype_struct(name, &$wrapper(value)) - } - - fn serialize_newtype_variant( - self, - name: &'static str, - variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - self.0 - .serialize_newtype_variant(name, variant_index, variant, &$wrapper(value)) - } - - fn serialize_none(self) -> Result { - self.0.serialize_none() - } - - fn serialize_some(self, value: &T) -> Result - where - T: Serialize, - { - self.0.serialize_some(&$wrapper(value)) - } - - fn serialize_seq(self, len: Option) -> Result { - self.0.serialize_seq(len).map($wrapper) - } - - fn serialize_tuple(self, len: usize) -> Result { - self.0.serialize_tuple(len).map($wrapper) - } - - fn serialize_tuple_struct( - self, - name: &'static str, - len: usize, - ) -> Result { - self.0.serialize_tuple_struct(name, len).map($wrapper) - } - - fn serialize_tuple_variant( - self, - name: &'static str, - variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - self.0 - .serialize_tuple_variant(name, variant_index, variant, len) - .map($wrapper) - } - - fn serialize_map(self, len: Option) -> Result { - self.0.serialize_map(len).map($wrapper) - } - - fn serialize_struct( - self, - name: &'static str, - len: usize, - ) -> Result { - self.0.serialize_struct(name, len).map($wrapper) - } - - fn serialize_struct_variant( - self, - name: &'static str, - variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - self.0 - .serialize_struct_variant(name, variant_index, variant, len) - .map($wrapper) - } - } - - impl SerializeSeq for $wrapper - where - S: SerializeSeq, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_element(&mut self, value: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_element(&$wrapper(value)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeTuple for $wrapper - where - S: SerializeTuple, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_element(&mut self, value: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_element(&$wrapper(value)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeTupleStruct for $wrapper - where - S: SerializeTupleStruct, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_field(&mut self, value: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_field(&$wrapper(value)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeTupleVariant for $wrapper - where - S: SerializeTupleVariant, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_field(&mut self, value: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_field(&$wrapper(value)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeMap for $wrapper - where - S: SerializeMap, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_key(&mut self, key: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_key(&$wrapper(key)) - } - fn serialize_value(&mut self, value: &T) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_value(&$wrapper(value)) - } - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), S::Error> - where - K: Serialize, - V: Serialize, - { - self.0.serialize_entry(key, &$wrapper(value)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeStruct for $wrapper - where - S: SerializeStruct, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_field( - &mut self, - name: &'static str, - field: &T, - ) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_field(name, &$wrapper(field)) - } - fn end(self) -> Result { - self.0.end() - } - } - - impl SerializeStructVariant for $wrapper - where - S: SerializeStructVariant, - { - type Ok = S::Ok; - type Error = S::Error; - fn serialize_field( - &mut self, - name: &'static str, - field: &T, - ) -> Result<(), S::Error> - where - T: Serialize, - { - self.0.serialize_field(name, &$wrapper(field)) - } - fn end(self) -> Result { - self.0.end() - } - } - }; -} - -impl_serializer!(Readable, true); -impl_serializer!(Compact, false); - -use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor}; - -macro_rules! forward_deserialize_methods { - ( $wrapper : ident ( $( $name: ident ),* ) ) => { - $( - fn $name(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - (self.0).$name($wrapper(visitor)) - } - )* - }; -} - -macro_rules! impl_deserializer { - ($wrapper:ident, $is_human_readable:expr) => { - impl<'de, D> Deserializer<'de> for $wrapper - where - D: Deserializer<'de>, - { - type Error = D::Error; - - forward_deserialize_methods! { - $wrapper ( - deserialize_any, - deserialize_bool, - deserialize_u8, - deserialize_u16, - deserialize_u32, - deserialize_u64, - deserialize_i8, - deserialize_i16, - deserialize_i32, - deserialize_i64, - deserialize_f32, - deserialize_f64, - deserialize_char, - deserialize_str, - deserialize_string, - deserialize_bytes, - deserialize_byte_buf, - deserialize_option, - deserialize_unit, - deserialize_seq, - deserialize_map, - deserialize_identifier, - deserialize_ignored_any - ) - } - - fn deserialize_unit_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0.deserialize_unit_struct(name, $wrapper(visitor)) - } - fn deserialize_newtype_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0.deserialize_newtype_struct(name, $wrapper(visitor)) - } - fn deserialize_tuple(self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.0.deserialize_tuple(len, $wrapper(visitor)) - } - fn deserialize_tuple_struct( - self, - name: &'static str, - len: usize, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0 - .deserialize_tuple_struct(name, len, $wrapper(visitor)) - } - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0.deserialize_struct(name, fields, $wrapper(visitor)) - } - fn deserialize_enum( - self, - name: &'static str, - variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0.deserialize_enum(name, variants, $wrapper(visitor)) - } - - fn is_human_readable(&self) -> bool { - $is_human_readable - } - } - - impl<'de, D> Visitor<'de> for $wrapper - where - D: Visitor<'de>, - { - type Value = D::Value; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.0.expecting(formatter) - } - fn visit_bool(self, v: bool) -> Result - where - E: Error, - { - self.0.visit_bool(v) - } - fn visit_i8(self, v: i8) -> Result - where - E: Error, - { - self.0.visit_i8(v) - } - fn visit_i16(self, v: i16) -> Result - where - E: Error, - { - self.0.visit_i16(v) - } - fn visit_i32(self, v: i32) -> Result - where - E: Error, - { - self.0.visit_i32(v) - } - fn visit_i64(self, v: i64) -> Result - where - E: Error, - { - self.0.visit_i64(v) - } - fn visit_u8(self, v: u8) -> Result - where - E: Error, - { - self.0.visit_u8(v) - } - fn visit_u16(self, v: u16) -> Result - where - E: Error, - { - self.0.visit_u16(v) - } - fn visit_u32(self, v: u32) -> Result - where - E: Error, - { - self.0.visit_u32(v) - } - fn visit_u64(self, v: u64) -> Result - where - E: Error, - { - self.0.visit_u64(v) - } - fn visit_f32(self, v: f32) -> Result - where - E: Error, - { - self.0.visit_f32(v) - } - fn visit_f64(self, v: f64) -> Result - where - E: Error, - { - self.0.visit_f64(v) - } - fn visit_char(self, v: char) -> Result - where - E: Error, - { - self.0.visit_char(v) - } - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - self.0.visit_str(v) - } - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: Error, - { - self.0.visit_borrowed_str(v) - } - fn visit_string(self, v: String) -> Result - where - E: Error, - { - self.0.visit_string(v) - } - fn visit_bytes(self, v: &[u8]) -> Result - where - E: Error, - { - self.0.visit_bytes(v) - } - fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result - where - E: Error, - { - self.0.visit_borrowed_bytes(v) - } - fn visit_byte_buf(self, v: Vec) -> Result - where - E: Error, - { - self.0.visit_byte_buf(v) - } - fn visit_none(self) -> Result - where - E: Error, - { - self.0.visit_none() - } - fn visit_some(self, deserializer: D2) -> Result - where - D2: Deserializer<'de>, - { - self.0.visit_some($wrapper(deserializer)) - } - fn visit_unit(self) -> Result - where - E: Error, - { - self.0.visit_unit() - } - fn visit_newtype_struct(self, deserializer: D2) -> Result - where - D2: Deserializer<'de>, - { - self.0.visit_newtype_struct($wrapper(deserializer)) - } - fn visit_seq(self, seq: V) -> Result - where - V: SeqAccess<'de>, - { - self.0.visit_seq($wrapper(seq)) - } - fn visit_map(self, map: V) -> Result - where - V: MapAccess<'de>, - { - self.0.visit_map($wrapper(map)) - } - fn visit_enum(self, data: V) -> Result - where - V: EnumAccess<'de>, - { - self.0.visit_enum($wrapper(data)) - } - } - - impl<'de, D> SeqAccess<'de> for $wrapper - where - D: SeqAccess<'de>, - { - type Error = D::Error; - fn next_element_seed(&mut self, seed: T) -> Result, D::Error> - where - T: DeserializeSeed<'de>, - { - self.0.next_element_seed($wrapper(seed)) - } - fn size_hint(&self) -> Option { - self.0.size_hint() - } - } - - impl<'de, D> MapAccess<'de> for $wrapper - where - D: MapAccess<'de>, - { - type Error = D::Error; - fn next_key_seed(&mut self, seed: K) -> Result, D::Error> - where - K: DeserializeSeed<'de>, - { - self.0.next_key_seed($wrapper(seed)) - } - fn next_value_seed(&mut self, seed: V) -> Result - where - V: DeserializeSeed<'de>, - { - self.0.next_value_seed($wrapper(seed)) - } - fn size_hint(&self) -> Option { - self.0.size_hint() - } - } - - impl<'de, D> EnumAccess<'de> for $wrapper - where - D: EnumAccess<'de>, - { - type Error = D::Error; - type Variant = $wrapper; - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> - where - V: DeserializeSeed<'de>, - { - self.0 - .variant_seed($wrapper(seed)) - .map(|(value, variant)| (value, $wrapper(variant))) - } - } - - impl<'de, D> VariantAccess<'de> for $wrapper - where - D: VariantAccess<'de>, - { - type Error = D::Error; - fn unit_variant(self) -> Result<(), D::Error> { - self.0.unit_variant() - } - fn newtype_variant_seed(self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { - self.0.newtype_variant_seed($wrapper(seed)) - } - fn tuple_variant(self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.0.tuple_variant(len, $wrapper(visitor)) - } - fn struct_variant( - self, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.0.struct_variant(fields, $wrapper(visitor)) - } - } - }; -} - -impl_deserializer!(Readable, true); -impl_deserializer!(Compact, false); diff --git a/serde_test/src/de.rs b/serde_test/src/de.rs deleted file mode 100644 index c9bcee5b3..000000000 --- a/serde_test/src/de.rs +++ /dev/null @@ -1,657 +0,0 @@ -use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer}; -use serde::de::{ - self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, - VariantAccess, Visitor, -}; - -use error::Error; -use token::Token; - -#[derive(Debug)] -pub struct Deserializer<'de> { - tokens: &'de [Token], -} - -macro_rules! assert_next_token { - ($de:expr, $expected:expr) => { - match $de.next_token_opt() { - Some(token) if token == $expected => {} - Some(other) => panic!( - "expected Token::{} but deserialization wants Token::{}", - other, $expected - ), - None => panic!( - "end of tokens but deserialization wants Token::{}", - $expected - ), - } - }; -} - -macro_rules! unexpected { - ($token:expr) => { - panic!("deserialization did not expect this token: {}", $token) - }; -} - -macro_rules! end_of_tokens { - () => { - panic!("ran out of tokens to deserialize") - }; -} - -impl<'de> Deserializer<'de> { - pub fn new(tokens: &'de [Token]) -> Self { - Deserializer { tokens: tokens } - } - - fn peek_token_opt(&self) -> Option { - self.tokens.first().cloned() - } - - fn peek_token(&self) -> Token { - match self.peek_token_opt() { - Some(token) => token, - None => end_of_tokens!(), - } - } - - pub fn next_token_opt(&mut self) -> Option { - match self.tokens.split_first() { - Some((&first, rest)) => { - self.tokens = rest; - Some(first) - } - None => None, - } - } - - fn next_token(&mut self) -> Token { - match self.tokens.split_first() { - Some((&first, rest)) => { - self.tokens = rest; - first - } - None => end_of_tokens!(), - } - } - - pub fn remaining(&self) -> usize { - self.tokens.len() - } - - fn visit_seq( - &mut self, - len: Option, - end: Token, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let value = visitor.visit_seq(DeserializerSeqVisitor { - de: self, - len: len, - end: end, - })?; - assert_next_token!(self, end); - Ok(value) - } - - fn visit_map( - &mut self, - len: Option, - end: Token, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let value = visitor.visit_map(DeserializerMapVisitor { - de: self, - len: len, - end: end, - })?; - assert_next_token!(self, end); - Ok(value) - } -} - -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { - type Error = Error; - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf unit seq map identifier ignored_any - } - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - let token = self.next_token(); - match token { - Token::Bool(v) => visitor.visit_bool(v), - Token::I8(v) => visitor.visit_i8(v), - Token::I16(v) => visitor.visit_i16(v), - Token::I32(v) => visitor.visit_i32(v), - Token::I64(v) => visitor.visit_i64(v), - Token::U8(v) => visitor.visit_u8(v), - Token::U16(v) => visitor.visit_u16(v), - Token::U32(v) => visitor.visit_u32(v), - Token::U64(v) => visitor.visit_u64(v), - Token::F32(v) => visitor.visit_f32(v), - Token::F64(v) => visitor.visit_f64(v), - Token::Char(v) => visitor.visit_char(v), - Token::Str(v) => visitor.visit_str(v), - Token::BorrowedStr(v) => visitor.visit_borrowed_str(v), - Token::String(v) => visitor.visit_string(v.to_owned()), - Token::Bytes(v) => visitor.visit_bytes(v), - Token::BorrowedBytes(v) => visitor.visit_borrowed_bytes(v), - Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()), - Token::None => visitor.visit_none(), - Token::Some => visitor.visit_some(self), - Token::Unit | Token::UnitStruct { .. } => visitor.visit_unit(), - Token::NewtypeStruct { .. } => visitor.visit_newtype_struct(self), - Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, visitor), - Token::Tuple { len } => self.visit_seq(Some(len), Token::TupleEnd, visitor), - Token::TupleStruct { len, .. } => { - self.visit_seq(Some(len), Token::TupleStructEnd, visitor) - } - Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor), - Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor), - Token::Enum { .. } => { - let variant = self.next_token(); - let next = self.peek_token(); - match (variant, next) { - (Token::Str(variant), Token::Unit) => { - self.next_token(); - visitor.visit_str(variant) - } - (Token::Bytes(variant), Token::Unit) => { - self.next_token(); - visitor.visit_bytes(variant) - } - (Token::U32(variant), Token::Unit) => { - self.next_token(); - visitor.visit_u32(variant) - } - (variant, Token::Unit) => unexpected!(variant), - (variant, _) => { - visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any)) - } - } - } - Token::UnitVariant { variant, .. } => visitor.visit_str(variant), - Token::NewtypeVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new( - self, - Token::Str(variant), - EnumFormat::Any, - )), - Token::TupleVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new( - self, - Token::Str(variant), - EnumFormat::Seq, - )), - Token::StructVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new( - self, - Token::Str(variant), - EnumFormat::Map, - )), - Token::SeqEnd - | Token::TupleEnd - | Token::TupleStructEnd - | Token::MapEnd - | Token::StructEnd - | Token::TupleVariantEnd - | Token::StructVariantEnd => { - unexpected!(token); - } - } - } - - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::Unit | Token::None => { - self.next_token(); - visitor.visit_none() - } - Token::Some => { - self.next_token(); - visitor.visit_some(self) - } - _ => self.deserialize_any(visitor), - } - } - - fn deserialize_enum( - self, - name: &'static str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::Enum { name: n } if name == n => { - self.next_token(); - - visitor.visit_enum(DeserializerEnumVisitor { de: self }) - } - Token::UnitVariant { name: n, .. } - | Token::NewtypeVariant { name: n, .. } - | Token::TupleVariant { name: n, .. } - | Token::StructVariant { name: n, .. } - if name == n => - { - visitor.visit_enum(DeserializerEnumVisitor { de: self }) - } - _ => { - unexpected!(self.next_token()); - } - } - } - - fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::UnitStruct { .. } => { - assert_next_token!(self, Token::UnitStruct { name: name }); - visitor.visit_unit() - } - _ => self.deserialize_any(visitor), - } - } - - fn deserialize_newtype_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::NewtypeStruct { .. } => { - assert_next_token!(self, Token::NewtypeStruct { name: name }); - visitor.visit_newtype_struct(self) - } - _ => self.deserialize_any(visitor), - } - } - - fn deserialize_tuple(self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::Unit | Token::UnitStruct { .. } => { - self.next_token(); - visitor.visit_unit() - } - Token::Seq { .. } => { - self.next_token(); - self.visit_seq(Some(len), Token::SeqEnd, visitor) - } - Token::Tuple { .. } => { - self.next_token(); - self.visit_seq(Some(len), Token::TupleEnd, visitor) - } - Token::TupleStruct { .. } => { - self.next_token(); - self.visit_seq(Some(len), Token::TupleStructEnd, visitor) - } - _ => self.deserialize_any(visitor), - } - } - - fn deserialize_tuple_struct( - self, - name: &'static str, - len: usize, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::Unit => { - self.next_token(); - visitor.visit_unit() - } - Token::UnitStruct { .. } => { - assert_next_token!(self, Token::UnitStruct { name: name }); - visitor.visit_unit() - } - Token::Seq { .. } => { - self.next_token(); - self.visit_seq(Some(len), Token::SeqEnd, visitor) - } - Token::Tuple { .. } => { - self.next_token(); - self.visit_seq(Some(len), Token::TupleEnd, visitor) - } - Token::TupleStruct { len: n, .. } => { - assert_next_token!(self, Token::TupleStruct { name: name, len: n }); - self.visit_seq(Some(len), Token::TupleStructEnd, visitor) - } - _ => self.deserialize_any(visitor), - } - } - - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.peek_token() { - Token::Struct { len: n, .. } => { - assert_next_token!(self, Token::Struct { name: name, len: n }); - self.visit_map(Some(fields.len()), Token::StructEnd, visitor) - } - Token::Map { .. } => { - self.next_token(); - self.visit_map(Some(fields.len()), Token::MapEnd, visitor) - } - _ => self.deserialize_any(visitor), - } - } - - fn is_human_readable(&self) -> bool { - panic!( - "Types which have different human-readable and compact representations \ - must explicitly mark their test cases with `serde_test::Configure`" - ); - } -} - -////////////////////////////////////////////////////////////////////////// - -struct DeserializerSeqVisitor<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, - len: Option, - end: Token, -} - -impl<'de, 'a> SeqAccess<'de> for DeserializerSeqVisitor<'a, 'de> { - type Error = Error; - - fn next_element_seed(&mut self, seed: T) -> Result, Error> - where - T: DeserializeSeed<'de>, - { - if self.de.peek_token_opt() == Some(self.end) { - return Ok(None); - } - self.len = self.len.map(|len| len.saturating_sub(1)); - seed.deserialize(&mut *self.de).map(Some) - } - - fn size_hint(&self) -> Option { - self.len - } -} - -////////////////////////////////////////////////////////////////////////// - -struct DeserializerMapVisitor<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, - len: Option, - end: Token, -} - -impl<'de, 'a> MapAccess<'de> for DeserializerMapVisitor<'a, 'de> { - type Error = Error; - - fn next_key_seed(&mut self, seed: K) -> Result, Error> - where - K: DeserializeSeed<'de>, - { - if self.de.peek_token_opt() == Some(self.end) { - return Ok(None); - } - self.len = self.len.map(|len| len.saturating_sub(1)); - seed.deserialize(&mut *self.de).map(Some) - } - - fn next_value_seed(&mut self, seed: V) -> Result - where - V: DeserializeSeed<'de>, - { - seed.deserialize(&mut *self.de) - } - - fn size_hint(&self) -> Option { - self.len - } -} - -////////////////////////////////////////////////////////////////////////// - -struct DeserializerEnumVisitor<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, -} - -impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> { - type Error = Error; - type Variant = Self; - - fn variant_seed(self, seed: V) -> Result<(V::Value, Self), Error> - where - V: DeserializeSeed<'de>, - { - match self.de.peek_token() { - Token::UnitVariant { variant: v, .. } - | Token::NewtypeVariant { variant: v, .. } - | Token::TupleVariant { variant: v, .. } - | Token::StructVariant { variant: v, .. } => { - let de = v.into_deserializer(); - let value = seed.deserialize(de)?; - Ok((value, self)) - } - _ => { - let value = seed.deserialize(&mut *self.de)?; - Ok((value, self)) - } - } - } -} - -impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> { - type Error = Error; - - fn unit_variant(self) -> Result<(), Error> { - match self.de.peek_token() { - Token::UnitVariant { .. } => { - self.de.next_token(); - Ok(()) - } - _ => Deserialize::deserialize(self.de), - } - } - - fn newtype_variant_seed(self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { - match self.de.peek_token() { - Token::NewtypeVariant { .. } => { - self.de.next_token(); - seed.deserialize(self.de) - } - _ => seed.deserialize(self.de), - } - } - - fn tuple_variant(self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.de.peek_token() { - Token::TupleVariant { len: enum_len, .. } => { - let token = self.de.next_token(); - - if len == enum_len { - self.de - .visit_seq(Some(len), Token::TupleVariantEnd, visitor) - } else { - unexpected!(token); - } - } - Token::Seq { - len: Some(enum_len), - } => { - let token = self.de.next_token(); - - if len == enum_len { - self.de.visit_seq(Some(len), Token::SeqEnd, visitor) - } else { - unexpected!(token); - } - } - _ => de::Deserializer::deserialize_any(self.de, visitor), - } - } - - fn struct_variant( - self, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - match self.de.peek_token() { - Token::StructVariant { len: enum_len, .. } => { - let token = self.de.next_token(); - - if fields.len() == enum_len { - self.de - .visit_map(Some(fields.len()), Token::StructVariantEnd, visitor) - } else { - unexpected!(token); - } - } - Token::Map { - len: Some(enum_len), - } => { - let token = self.de.next_token(); - - if fields.len() == enum_len { - self.de - .visit_map(Some(fields.len()), Token::MapEnd, visitor) - } else { - unexpected!(token); - } - } - _ => de::Deserializer::deserialize_any(self.de, visitor), - } - } -} - -////////////////////////////////////////////////////////////////////////// - -struct EnumMapVisitor<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, - variant: Option, - format: EnumFormat, -} - -enum EnumFormat { - Seq, - Map, - Any, -} - -impl<'a, 'de> EnumMapVisitor<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>, variant: Token, format: EnumFormat) -> Self { - EnumMapVisitor { - de: de, - variant: Some(variant), - format: format, - } - } -} - -impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> { - type Error = Error; - - fn next_key_seed(&mut self, seed: K) -> Result, Error> - where - K: DeserializeSeed<'de>, - { - match self.variant.take() { - Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), - Some(Token::Bytes(variant)) => seed - .deserialize(BytesDeserializer { value: variant }) - .map(Some), - Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), - Some(other) => unexpected!(other), - None => Ok(None), - } - } - - fn next_value_seed(&mut self, seed: V) -> Result - where - V: DeserializeSeed<'de>, - { - match self.format { - EnumFormat::Seq => { - let value = { - let visitor = DeserializerSeqVisitor { - de: self.de, - len: None, - end: Token::TupleVariantEnd, - }; - seed.deserialize(SeqAccessDeserializer::new(visitor))? - }; - assert_next_token!(self.de, Token::TupleVariantEnd); - Ok(value) - } - EnumFormat::Map => { - let value = { - let visitor = DeserializerMapVisitor { - de: self.de, - len: None, - end: Token::StructVariantEnd, - }; - seed.deserialize(MapAccessDeserializer::new(visitor))? - }; - assert_next_token!(self.de, Token::StructVariantEnd); - Ok(value) - } - EnumFormat::Any => seed.deserialize(&mut *self.de), - } - } -} - -struct BytesDeserializer { - value: &'static [u8], -} - -impl<'de> de::Deserializer<'de> for BytesDeserializer { - type Error = Error; - - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_bytes(self.value) - } - - 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 - } -} diff --git a/serde_test/src/error.rs b/serde_test/src/error.rs deleted file mode 100644 index 54a71d2d8..000000000 --- a/serde_test/src/error.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::error; -use std::fmt::{self, Display}; - -use serde::{de, ser}; - -#[derive(Clone, Debug)] -pub struct Error { - msg: String, -} - -impl ser::Error for Error { - fn custom(msg: T) -> Self { - Error { - msg: msg.to_string(), - } - } -} - -impl de::Error for Error { - fn custom(msg: T) -> Self { - Error { - msg: msg.to_string(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(&self.msg) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - &self.msg - } -} - -impl PartialEq for Error { - fn eq(&self, other: &str) -> bool { - self.msg == other - } -} diff --git a/serde_test/src/lib.rs b/serde_test/src/lib.rs deleted file mode 100644 index 3a3efe352..000000000 --- a/serde_test/src/lib.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! This crate provides a convenient concise way to write unit tests for -//! implementations of [`Serialize`] and [`Deserialize`]. -//! -//! [`Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html -//! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html -//! -//! The `Serialize` impl for a value can be characterized by the sequence of -//! [`Serializer`] calls that are made in the course of serializing the value, -//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly -//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to -//! test that a value serializes to a particular sequence of method calls, an -//! [`assert_de_tokens`] function to test that a value can be deserialized from -//! a particular sequence of method calls, and an [`assert_tokens`] function to -//! test both directions. There are also functions to test expected failure -//! conditions. -//! -//! [`Serializer`]: https://docs.serde.rs/serde/ser/trait.Serializer.html -//! [`Token`]: https://docs.serde.rs/serde_test/enum.Token.html -//! [`assert_ser_tokens`]: https://docs.serde.rs/serde_test/fn.assert_ser_tokens.html -//! [`assert_de_tokens`]: https://docs.serde.rs/serde_test/fn.assert_de_tokens.html -//! [`assert_tokens`]: https://docs.serde.rs/serde_test/fn.assert_tokens.html -//! -//! Here is an example from the [`linked-hash-map`] crate. -//! -//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map -//! -//! ```edition2018 -//! # const IGNORE: &str = stringify! { -//! use linked_hash_map::LinkedHashMap; -//! # }; -//! use serde_test::{Token, assert_tokens}; -//! -//! # use std::fmt; -//! # use std::marker::PhantomData; -//! # -//! # use serde::ser::{Serialize, Serializer, SerializeMap}; -//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess}; -//! # -//! # // Dumb imitation of LinkedHashMap. -//! # #[derive(PartialEq, Debug)] -//! # struct LinkedHashMap(Vec<(K, V)>); -//! # -//! # impl LinkedHashMap { -//! # fn new() -> Self { -//! # LinkedHashMap(Vec::new()) -//! # } -//! # -//! # fn insert(&mut self, k: K, v: V) { -//! # self.0.push((k, v)); -//! # } -//! # } -//! # -//! # impl Serialize for LinkedHashMap -//! # where -//! # K: Serialize, -//! # V: Serialize, -//! # { -//! # fn serialize(&self, serializer: S) -> Result -//! # where -//! # S: Serializer, -//! # { -//! # let mut map = serializer.serialize_map(Some(self.0.len()))?; -//! # for &(ref k, ref v) in &self.0 { -//! # map.serialize_entry(k, v)?; -//! # } -//! # map.end() -//! # } -//! # } -//! # -//! # struct LinkedHashMapVisitor(PhantomData<(K, V)>); -//! # -//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor -//! # where -//! # K: Deserialize<'de>, -//! # V: Deserialize<'de>, -//! # { -//! # type Value = LinkedHashMap; -//! # -//! # fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result { -//! # unimplemented!() -//! # } -//! # -//! # fn visit_map(self, mut access: M) -> Result -//! # where -//! # M: MapAccess<'de>, -//! # { -//! # let mut map = LinkedHashMap::new(); -//! # while let Some((key, value)) = access.next_entry()? { -//! # map.insert(key, value); -//! # } -//! # Ok(map) -//! # } -//! # } -//! # -//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap -//! # where -//! # K: Deserialize<'de>, -//! # V: Deserialize<'de>, -//! # { -//! # fn deserialize(deserializer: D) -> Result -//! # where -//! # D: Deserializer<'de>, -//! # { -//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData)) -//! # } -//! # } -//! # -//! #[test] -//! # fn not_a_test_ser_de_empty() {} -//! fn test_ser_de_empty() { -//! let map = LinkedHashMap::::new(); -//! -//! assert_tokens(&map, &[ -//! Token::Map { len: Some(0) }, -//! Token::MapEnd, -//! ]); -//! } -//! -//! #[test] -//! # fn not_a_test_ser_de() {} -//! fn test_ser_de() { -//! let mut map = LinkedHashMap::new(); -//! map.insert('b', 20); -//! map.insert('a', 10); -//! map.insert('c', 30); -//! -//! assert_tokens(&map, &[ -//! Token::Map { len: Some(3) }, -//! Token::Char('b'), -//! Token::I32(20), -//! -//! Token::Char('a'), -//! Token::I32(10), -//! -//! Token::Char('c'), -//! Token::I32(30), -//! Token::MapEnd, -//! ]); -//! } -//! # -//! # fn main() { -//! # test_ser_de_empty(); -//! # test_ser_de(); -//! # } -//! ``` - -#![doc(html_root_url = "https://docs.rs/serde_test/1.0.118")] -#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] -// Ignored clippy lints -#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))] -// Ignored clippy_pedantic lints -#![cfg_attr( - feature = "cargo-clippy", - allow( - empty_line_after_outer_attr, - missing_docs_in_private_items, - module_name_repetitions, - must_use_candidate, - redundant_field_names, - use_debug, - use_self - ) -)] - -#[macro_use] -extern crate serde; - -mod de; -mod error; -mod ser; - -mod assert; -mod configure; -mod token; - -pub use assert::{ - assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error, - assert_tokens, -}; -pub use token::Token; - -pub use configure::{Compact, Configure, Readable}; - -// Not public API. -#[doc(hidden)] -pub use de::Deserializer; diff --git a/serde_test/src/ser.rs b/serde_test/src/ser.rs deleted file mode 100644 index 0ff6c8289..000000000 --- a/serde_test/src/ser.rs +++ /dev/null @@ -1,464 +0,0 @@ -use serde::{ser, Serialize}; - -use error::Error; -use token::Token; - -/// A `Serializer` that ensures that a value serializes to a given list of -/// tokens. -#[derive(Debug)] -pub struct Serializer<'a> { - tokens: &'a [Token], -} - -impl<'a> Serializer<'a> { - /// Creates the serializer. - pub fn new(tokens: &'a [Token]) -> Self { - Serializer { tokens: tokens } - } - - /// Pulls the next token off of the serializer, ignoring it. - fn next_token(&mut self) -> Option { - if let Some((&first, rest)) = self.tokens.split_first() { - self.tokens = rest; - Some(first) - } else { - None - } - } - - pub fn remaining(&self) -> usize { - self.tokens.len() - } -} - -macro_rules! assert_next_token { - ($ser:expr, $expected:ident) => { - assert_next_token!($ser, stringify!($expected), Token::$expected, true); - }; - ($ser:expr, $expected:ident($v:expr)) => { - assert_next_token!( - $ser, - format_args!(concat!(stringify!($expected), "({:?})"), $v), - Token::$expected(v), - v == $v - ); - }; - ($ser:expr, $expected:ident { $($k:ident),* }) => { - let compare = ($($k,)*); - let field_format = || { - use std::fmt::Write; - let mut buffer = String::new(); - $( - write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap(); - )* - buffer - }; - assert_next_token!( - $ser, - format_args!(concat!(stringify!($expected), " {{ {}}}"), field_format()), - Token::$expected { $($k),* }, - ($($k,)*) == compare - ); - }; - ($ser:expr, $expected:expr, $pat:pat, $guard:expr) => { - match $ser.next_token() { - Some($pat) if $guard => {} - Some(other) => { - panic!("expected Token::{} but serialized as {}", - $expected, other); - } - None => { - panic!("expected Token::{} after end of serialized tokens", - $expected); - } - } - }; -} - -impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - type SerializeSeq = Self; - type SerializeTuple = Self; - type SerializeTupleStruct = Self; - type SerializeTupleVariant = Variant<'s, 'a>; - type SerializeMap = Self; - type SerializeStruct = Self; - type SerializeStructVariant = Variant<'s, 'a>; - - fn serialize_bool(self, v: bool) -> Result<(), Error> { - assert_next_token!(self, Bool(v)); - Ok(()) - } - - fn serialize_i8(self, v: i8) -> Result<(), Error> { - assert_next_token!(self, I8(v)); - Ok(()) - } - - fn serialize_i16(self, v: i16) -> Result<(), Error> { - assert_next_token!(self, I16(v)); - Ok(()) - } - - fn serialize_i32(self, v: i32) -> Result<(), Error> { - assert_next_token!(self, I32(v)); - Ok(()) - } - - fn serialize_i64(self, v: i64) -> Result<(), Error> { - assert_next_token!(self, I64(v)); - Ok(()) - } - - fn serialize_u8(self, v: u8) -> Result<(), Error> { - assert_next_token!(self, U8(v)); - Ok(()) - } - - fn serialize_u16(self, v: u16) -> Result<(), Error> { - assert_next_token!(self, U16(v)); - Ok(()) - } - - fn serialize_u32(self, v: u32) -> Result<(), Error> { - assert_next_token!(self, U32(v)); - Ok(()) - } - - fn serialize_u64(self, v: u64) -> Result<(), Error> { - assert_next_token!(self, U64(v)); - Ok(()) - } - - fn serialize_f32(self, v: f32) -> Result<(), Error> { - assert_next_token!(self, F32(v)); - Ok(()) - } - - fn serialize_f64(self, v: f64) -> Result<(), Error> { - assert_next_token!(self, F64(v)); - Ok(()) - } - - fn serialize_char(self, v: char) -> Result<(), Error> { - assert_next_token!(self, Char(v)); - Ok(()) - } - - fn serialize_str(self, v: &str) -> Result<(), Error> { - match self.tokens.first() { - Some(&Token::BorrowedStr(_)) => assert_next_token!(self, BorrowedStr(v)), - Some(&Token::String(_)) => assert_next_token!(self, String(v)), - _ => assert_next_token!(self, Str(v)), - } - Ok(()) - } - - fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> { - match self.tokens.first() { - Some(&Token::BorrowedBytes(_)) => assert_next_token!(self, BorrowedBytes(v)), - Some(&Token::ByteBuf(_)) => assert_next_token!(self, ByteBuf(v)), - _ => assert_next_token!(self, Bytes(v)), - } - Ok(()) - } - - fn serialize_unit(self) -> Result<(), Error> { - assert_next_token!(self, Unit); - Ok(()) - } - - fn serialize_unit_struct(self, name: &'static str) -> Result<(), Error> { - assert_next_token!(self, UnitStruct { name }); - Ok(()) - } - - fn serialize_unit_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result<(), Error> { - if self.tokens.first() == Some(&Token::Enum { name: name }) { - self.next_token(); - assert_next_token!(self, Str(variant)); - assert_next_token!(self, Unit); - } else { - assert_next_token!(self, UnitVariant { name, variant }); - } - Ok(()) - } - - fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result<(), Error> - where - T: Serialize, - { - assert_next_token!(self, NewtypeStruct { name }); - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result<(), Error> - where - T: Serialize, - { - if self.tokens.first() == Some(&Token::Enum { name: name }) { - self.next_token(); - assert_next_token!(self, Str(variant)); - } else { - assert_next_token!(self, NewtypeVariant { name, variant }); - } - value.serialize(self) - } - - fn serialize_none(self) -> Result<(), Error> { - assert_next_token!(self, None); - Ok(()) - } - - fn serialize_some(self, value: &T) -> Result<(), Error> - where - T: Serialize, - { - assert_next_token!(self, Some); - value.serialize(self) - } - - fn serialize_seq(self, len: Option) -> Result { - assert_next_token!(self, Seq { len }); - Ok(self) - } - - fn serialize_tuple(self, len: usize) -> Result { - assert_next_token!(self, Tuple { len }); - Ok(self) - } - - fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result { - assert_next_token!(self, TupleStruct { name, len }); - Ok(self) - } - - fn serialize_tuple_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - if self.tokens.first() == Some(&Token::Enum { name: name }) { - self.next_token(); - assert_next_token!(self, Str(variant)); - let len = Some(len); - assert_next_token!(self, Seq { len }); - Ok(Variant { - ser: self, - end: Token::SeqEnd, - }) - } else { - assert_next_token!(self, TupleVariant { name, variant, len }); - Ok(Variant { - ser: self, - end: Token::TupleVariantEnd, - }) - } - } - - fn serialize_map(self, len: Option) -> Result { - assert_next_token!(self, Map { len }); - Ok(self) - } - - fn serialize_struct(self, name: &'static str, len: usize) -> Result { - assert_next_token!(self, Struct { name, len }); - Ok(self) - } - - fn serialize_struct_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - if self.tokens.first() == Some(&Token::Enum { name: name }) { - self.next_token(); - assert_next_token!(self, Str(variant)); - let len = Some(len); - assert_next_token!(self, Map { len }); - Ok(Variant { - ser: self, - end: Token::MapEnd, - }) - } else { - assert_next_token!(self, StructVariant { name, variant, len }); - Ok(Variant { - ser: self, - end: Token::StructVariantEnd, - }) - } - } - - fn is_human_readable(&self) -> bool { - panic!( - "Types which have different human-readable and compact representations \ - must explicitly mark their test cases with `serde_test::Configure`" - ); - } -} - -pub struct Variant<'s, 'a: 's> { - ser: &'s mut Serializer<'a>, - end: Token, -} - -impl<'s, 'a> ser::SerializeSeq for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Error> - where - T: Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result<(), Error> { - assert_next_token!(self, SeqEnd); - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeTuple for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Error> - where - T: Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result<(), Error> { - assert_next_token!(self, TupleEnd); - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeTupleStruct for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<(), Error> - where - T: Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result<(), Error> { - assert_next_token!(self, TupleStructEnd); - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeTupleVariant for Variant<'s, 'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<(), Error> - where - T: Serialize, - { - value.serialize(&mut *self.ser) - } - - fn end(self) -> Result<(), Error> { - match self.end { - Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd), - Token::SeqEnd => assert_next_token!(self.ser, SeqEnd), - _ => unreachable!(), - } - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeMap for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - key.serialize(&mut **self) - } - - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result<(), Self::Error> { - assert_next_token!(self, MapEnd); - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> - where - T: Serialize, - { - key.serialize(&mut **self)?; - value.serialize(&mut **self) - } - - fn end(self) -> Result<(), Self::Error> { - assert_next_token!(self, StructEnd); - Ok(()) - } -} - -impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> { - type Ok = (); - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> - where - T: Serialize, - { - key.serialize(&mut *self.ser)?; - value.serialize(&mut *self.ser) - } - - fn end(self) -> Result<(), Self::Error> { - match self.end { - Token::StructVariantEnd => assert_next_token!(self.ser, StructVariantEnd), - Token::MapEnd => assert_next_token!(self.ser, MapEnd), - _ => unreachable!(), - } - Ok(()) - } -} diff --git a/serde_test/src/token.rs b/serde_test/src/token.rs deleted file mode 100644 index 225136144..000000000 --- a/serde_test/src/token.rs +++ /dev/null @@ -1,519 +0,0 @@ -use std::fmt::{self, Debug, Display}; - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum Token { - /// A serialized `bool`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&true, &[Token::Bool(true)]); - /// ``` - Bool(bool), - - /// A serialized `i8`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0i8, &[Token::I8(0)]); - /// ``` - I8(i8), - - /// A serialized `i16`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0i16, &[Token::I16(0)]); - /// ``` - I16(i16), - - /// A serialized `i32`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0i32, &[Token::I32(0)]); - /// ``` - I32(i32), - - /// A serialized `i64`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0i64, &[Token::I64(0)]); - /// ``` - I64(i64), - - /// A serialized `u8`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0u8, &[Token::U8(0)]); - /// ``` - U8(u8), - - /// A serialized `u16`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0u16, &[Token::U16(0)]); - /// ``` - U16(u16), - - /// A serialized `u32`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0u32, &[Token::U32(0)]); - /// ``` - U32(u32), - - /// A serialized `u64`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0u64, &[Token::U64(0)]); - /// ``` - U64(u64), - - /// A serialized `f32`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0f32, &[Token::F32(0.0)]); - /// ``` - F32(f32), - - /// A serialized `f64`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&0f64, &[Token::F64(0.0)]); - /// ``` - F64(f64), - - /// A serialized `char`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&'\n', &[Token::Char('\n')]); - /// ``` - Char(char), - - /// A serialized `str`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let s = String::from("transient"); - /// assert_tokens(&s, &[Token::Str("transient")]); - /// ``` - Str(&'static str), - - /// A borrowed `str`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let s: &str = "borrowed"; - /// assert_tokens(&s, &[Token::BorrowedStr("borrowed")]); - /// ``` - BorrowedStr(&'static str), - - /// A serialized `String`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let s = String::from("owned"); - /// assert_tokens(&s, &[Token::String("owned")]); - /// ``` - String(&'static str), - - /// A serialized `[u8]` - Bytes(&'static [u8]), - - /// A borrowed `[u8]`. - BorrowedBytes(&'static [u8]), - - /// A serialized `ByteBuf` - ByteBuf(&'static [u8]), - - /// A serialized `Option` containing none. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let opt = None::; - /// assert_tokens(&opt, &[Token::None]); - /// ``` - None, - - /// The header to a serialized `Option` containing some value. - /// - /// The tokens of the value follow after this header. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let opt = Some('c'); - /// assert_tokens(&opt, &[ - /// Token::Some, - /// Token::Char('c'), - /// ]); - /// ``` - Some, - - /// A serialized `()`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// assert_tokens(&(), &[Token::Unit]); - /// ``` - Unit, - - /// A serialized unit struct of the given name. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// struct X; - /// - /// assert_tokens(&X, &[Token::UnitStruct { name: "X" }]); - /// # } - /// ``` - UnitStruct { name: &'static str }, - - /// A unit variant of an enum. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// enum E { - /// A, - /// } - /// - /// let a = E::A; - /// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]); - /// # } - /// ``` - UnitVariant { - name: &'static str, - variant: &'static str, - }, - - /// The header to a serialized newtype struct of the given name. - /// - /// After this header is the value contained in the newtype struct. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// struct N(String); - /// - /// let n = N("newtype".to_owned()); - /// assert_tokens(&n, &[ - /// Token::NewtypeStruct { name: "N" }, - /// Token::String("newtype"), - /// ]); - /// # } - /// ``` - NewtypeStruct { name: &'static str }, - - /// The header to a newtype variant of an enum. - /// - /// After this header is the value contained in the newtype variant. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// enum E { - /// B(u8), - /// } - /// - /// let b = E::B(0); - /// assert_tokens(&b, &[ - /// Token::NewtypeVariant { name: "E", variant: "B" }, - /// Token::U8(0), - /// ]); - /// # } - /// ``` - NewtypeVariant { - name: &'static str, - variant: &'static str, - }, - - /// The header to a sequence. - /// - /// After this header are the elements of the sequence, followed by - /// `SeqEnd`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let vec = vec!['a', 'b', 'c']; - /// assert_tokens(&vec, &[ - /// Token::Seq { len: Some(3) }, - /// Token::Char('a'), - /// Token::Char('b'), - /// Token::Char('c'), - /// Token::SeqEnd, - /// ]); - /// ``` - Seq { len: Option }, - - /// An indicator of the end of a sequence. - SeqEnd, - - /// The header to a tuple. - /// - /// After this header are the elements of the tuple, followed by `TupleEnd`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// let tuple = ('a', 100); - /// assert_tokens(&tuple, &[ - /// Token::Tuple { len: 2 }, - /// Token::Char('a'), - /// Token::I32(100), - /// Token::TupleEnd, - /// ]); - /// ``` - Tuple { len: usize }, - - /// An indicator of the end of a tuple. - TupleEnd, - - /// The header to a tuple struct. - /// - /// After this header are the fields of the tuple struct, followed by - /// `TupleStructEnd`. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// struct T(u8, u8); - /// - /// let t = T(0, 0); - /// assert_tokens(&t, &[ - /// Token::TupleStruct { name: "T", len: 2 }, - /// Token::U8(0), - /// Token::U8(0), - /// Token::TupleStructEnd, - /// ]); - /// # } - /// ``` - TupleStruct { name: &'static str, len: usize }, - - /// An indicator of the end of a tuple struct. - TupleStructEnd, - - /// The header to a tuple variant of an enum. - /// - /// After this header are the fields of the tuple variant, followed by - /// `TupleVariantEnd`. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// enum E { - /// C(u8, u8), - /// } - /// - /// let c = E::C(0, 0); - /// assert_tokens(&c, &[ - /// Token::TupleVariant { name: "E", variant: "C", len: 2 }, - /// Token::U8(0), - /// Token::U8(0), - /// Token::TupleVariantEnd, - /// ]); - /// # } - /// ``` - TupleVariant { - name: &'static str, - variant: &'static str, - len: usize, - }, - - /// An indicator of the end of a tuple variant. - TupleVariantEnd, - - /// The header to a map. - /// - /// After this header are the entries of the map, followed by `MapEnd`. - /// - /// ```edition2018 - /// # use serde_test::{assert_tokens, Token}; - /// # - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert('A', 65); - /// map.insert('Z', 90); - /// - /// assert_tokens(&map, &[ - /// Token::Map { len: Some(2) }, - /// Token::Char('A'), - /// Token::I32(65), - /// Token::Char('Z'), - /// Token::I32(90), - /// Token::MapEnd, - /// ]); - /// ``` - Map { len: Option }, - - /// An indicator of the end of a map. - MapEnd, - - /// The header of a struct. - /// - /// After this header are the fields of the struct, followed by `StructEnd`. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// struct S { - /// a: u8, - /// b: u8, - /// } - /// - /// let s = S { a: 0, b: 0 }; - /// assert_tokens(&s, &[ - /// Token::Struct { name: "S", len: 2 }, - /// Token::Str("a"), - /// Token::U8(0), - /// Token::Str("b"), - /// Token::U8(0), - /// Token::StructEnd, - /// ]); - /// # } - /// ``` - Struct { name: &'static str, len: usize }, - - /// An indicator of the end of a struct. - StructEnd, - - /// The header of a struct variant of an enum. - /// - /// After this header are the fields of the struct variant, followed by - /// `StructVariantEnd`. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// enum E { - /// D { d: u8 }, - /// } - /// - /// let d = E::D { d: 0 }; - /// assert_tokens(&d, &[ - /// Token::StructVariant { name: "E", variant: "D", len: 1 }, - /// Token::Str("d"), - /// Token::U8(0), - /// Token::StructVariantEnd, - /// ]); - /// # } - /// ``` - StructVariant { - name: &'static str, - variant: &'static str, - len: usize, - }, - - /// An indicator of the end of a struct variant. - StructVariantEnd, - - /// The header to an enum of the given name. - /// - /// ```edition2018 - /// # use serde::{Serialize, Deserialize}; - /// # use serde_test::{assert_tokens, Token}; - /// # - /// # fn main() { - /// #[derive(Serialize, Deserialize, PartialEq, Debug)] - /// enum E { - /// A, - /// B(u8), - /// C(u8, u8), - /// D { d: u8 }, - /// } - /// - /// let a = E::A; - /// assert_tokens(&a, &[ - /// Token::Enum { name: "E" }, - /// Token::Str("A"), - /// Token::Unit, - /// ]); - /// - /// let b = E::B(0); - /// assert_tokens(&b, &[ - /// Token::Enum { name: "E" }, - /// Token::Str("B"), - /// Token::U8(0), - /// ]); - /// - /// let c = E::C(0, 0); - /// assert_tokens(&c, &[ - /// Token::Enum { name: "E" }, - /// Token::Str("C"), - /// Token::Seq { len: Some(2) }, - /// Token::U8(0), - /// Token::U8(0), - /// Token::SeqEnd, - /// ]); - /// - /// let d = E::D { d: 0 }; - /// assert_tokens(&d, &[ - /// Token::Enum { name: "E" }, - /// Token::Str("D"), - /// Token::Map { len: Some(1) }, - /// Token::Str("d"), - /// Token::U8(0), - /// Token::MapEnd, - /// ]); - /// # } - /// ``` - Enum { name: &'static str }, -} - -impl Display for Token { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - Debug::fmt(self, formatter) - } -} diff --git a/test_suite/Cargo.toml b/test_suite/Cargo.toml index 53effd4eb..df1cdc372 100644 --- a/test_suite/Cargo.toml +++ b/test_suite/Cargo.toml @@ -2,25 +2,20 @@ name = "serde_test_suite" version = "0.0.0" authors = ["Erick Tryzelaar ", "David Tolnay "] -edition = "2018" +edition = "2021" publish = false -build = "build.rs" [features] -expandtest = [] unstable = ["serde/unstable"] [dependencies] serde = { path = "../serde" } -[build-dependencies] -toolchain_find = "0.1" - [dev-dependencies] -fnv = "1.0" -macrotest = "=1.0.0" +automod = "1.0.1" +foldhash = "0.2" rustversion = "1.0" -serde = { path = "../serde", features = ["rc", "derive"] } +serde = { path = "../serde", features = ["rc"] } serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] } -serde_test = { path = "../serde_test" } -trybuild = { version = "1.0.19", features = ["diff"] } +serde_test = "1.0.176" +trybuild = { version = "1.0.108", features = ["diff"] } diff --git a/test_suite/build.rs b/test_suite/build.rs deleted file mode 100644 index 4ead539fc..000000000 --- a/test_suite/build.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::process::{Command, ExitStatus, Stdio}; - -fn has_cargo_expand() -> bool { - let cargo_expand = if cfg!(windows) { - "cargo-expand.exe" - } else { - "cargo-expand" - }; - - Command::new(cargo_expand) - .arg("--version") - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .as_ref() - .map(ExitStatus::success) - .unwrap_or(false) -} - -fn has_rustfmt() -> bool { - toolchain_find::find_installed_component("rustfmt").is_some() -} - -fn main() { - if cfg!(feature = "expandtest") && has_cargo_expand() && has_rustfmt() { - println!("cargo:rustc-cfg=expandtest"); - } -} diff --git a/test_suite/no_std/.gitignore b/test_suite/no_std/.gitignore new file mode 100644 index 000000000..e9e21997b --- /dev/null +++ b/test_suite/no_std/.gitignore @@ -0,0 +1,2 @@ +/target/ +/Cargo.lock diff --git a/test_suite/no_std/Cargo.toml b/test_suite/no_std/Cargo.toml index 8746960c2..7909a2d6b 100644 --- a/test_suite/no_std/Cargo.toml +++ b/test_suite/no_std/Cargo.toml @@ -1,11 +1,19 @@ [package] name = "serde_derive_tests_no_std" version = "0.0.0" -edition = "2018" +authors = ["David Tolnay "] +edition = "2021" publish = false [dependencies] libc = { version = "0.2", default-features = false } -serde = { path = "../../serde", default-features = false, features = ["derive"] } +serde = { path = "../../serde", default-features = false } +serde_derive = { path = "../../serde_derive" } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" [workspace] diff --git a/test_suite/no_std/src/main.rs b/test_suite/no_std/src/main.rs index deb32c5f3..71d553e10 100644 --- a/test_suite/no_std/src/main.rs +++ b/test_suite/no_std/src/main.rs @@ -1,14 +1,12 @@ -#![feature(lang_items, start)] #![no_std] +#![no_main] -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} +use core::ffi::c_int; -#[lang = "eh_personality"] #[no_mangle] -pub extern "C" fn rust_eh_personality() {} +extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int { + 0 +} #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { @@ -19,24 +17,24 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { ////////////////////////////////////////////////////////////////////////////// -use serde::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] -struct Unit; +pub struct Unit; #[derive(Serialize, Deserialize)] -struct Newtype(u8); +pub struct Newtype(u8); #[derive(Serialize, Deserialize)] -struct Tuple(u8, u8); +pub struct Tuple(u8, u8); #[derive(Serialize, Deserialize)] -struct Struct { +pub struct Struct { f: u8, } #[derive(Serialize, Deserialize)] -enum Enum { +pub enum Enum { Unit, Newtype(u8), Tuple(u8, u8), diff --git a/test_suite/tests/compiletest.rs b/test_suite/tests/compiletest.rs index 7118b9b3b..8ab6342f2 100644 --- a/test_suite/tests/compiletest.rs +++ b/test_suite/tests/compiletest.rs @@ -1,5 +1,7 @@ -#[cfg_attr(target_os = "emscripten", ignore)] -#[rustversion::attr(not(nightly), ignore)] +#[cfg_attr(target_os = "emscripten", ignore = "disabled on Emscripten")] +#[rustversion::attr(not(nightly), ignore = "requires nightly")] +#[cfg_attr(miri, ignore = "incompatible with miri")] +#[allow(unused_attributes)] #[test] fn ui() { let t = trybuild::TestCases::new(); diff --git a/test_suite/tests/expand/de_enum.expanded.rs b/test_suite/tests/expand/de_enum.expanded.rs deleted file mode 100644 index a4ba24911..000000000 --- a/test_suite/tests/expand/de_enum.expanded.rs +++ /dev/null @@ -1,1418 +0,0 @@ -use serde::{Deserialize, Serialize}; -enum DeEnum { - Unit, - Seq(i8, B, C, D), - Map { a: i8, b: B, c: C, d: D }, - _Unit2, - _Seq2(i8, B, C, D), - _Map2 { a: i8, b: B, c: C, d: D }, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for DeEnum - where - B: _serde::Serialize, - C: _serde::Serialize, - D: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - match *self { - DeEnum::Unit => { - _serde::Serializer::serialize_unit_variant(__serializer, "DeEnum", 0u32, "Unit") - } - DeEnum::Seq(ref __field0, ref __field1, ref __field2, ref __field3) => { - let mut __serde_state = match _serde::Serializer::serialize_tuple_variant( - __serializer, - "DeEnum", - 1u32, - "Seq", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field0, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field2, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field3, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleVariant::end(__serde_state) - } - DeEnum::Map { - ref a, - ref b, - ref c, - ref d, - } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "DeEnum", - 2u32, - "Map", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "b", - b, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "c", - c, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "d", - d, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - DeEnum::_Unit2 => _serde::Serializer::serialize_unit_variant( - __serializer, - "DeEnum", - 3u32, - "_Unit2", - ), - DeEnum::_Seq2(ref __field0, ref __field1, ref __field2, ref __field3) => { - let mut __serde_state = match _serde::Serializer::serialize_tuple_variant( - __serializer, - "DeEnum", - 4u32, - "_Seq2", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field0, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field2, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field3, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleVariant::end(__serde_state) - } - DeEnum::_Map2 { - ref a, - ref b, - ref c, - ref d, - } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "DeEnum", - 5u32, - "_Map2", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "b", - b, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "c", - c, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "d", - d, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - } - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, B, C, D> _serde::Deserialize<'de> for DeEnum - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __field3, - __field4, - __field5, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "variant identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - 3u64 => _serde::export::Ok(__Field::__field3), - 4u64 => _serde::export::Ok(__Field::__field4), - 5u64 => _serde::export::Ok(__Field::__field5), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"variant index 0 <= i < 6", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "Unit" => _serde::export::Ok(__Field::__field0), - "Seq" => _serde::export::Ok(__Field::__field1), - "Map" => _serde::export::Ok(__Field::__field2), - "_Unit2" => _serde::export::Ok(__Field::__field3), - "_Seq2" => _serde::export::Ok(__Field::__field4), - "_Map2" => _serde::export::Ok(__Field::__field5), - _ => _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"Unit" => _serde::export::Ok(__Field::__field0), - b"Seq" => _serde::export::Ok(__Field::__field1), - b"Map" => _serde::export::Ok(__Field::__field2), - b"_Unit2" => _serde::export::Ok(__Field::__field3), - b"_Seq2" => _serde::export::Ok(__Field::__field4), - b"_Map2" => _serde::export::Ok(__Field::__field5), - _ => { - let __value = &_serde::export::from_utf8_lossy(__value); - _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )) - } - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, B, C, D> _serde::de::Visitor<'de> for __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - type Value = DeEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "enum DeEnum") - } - fn visit_enum<__A>( - self, - __data: __A, - ) -> _serde::export::Result - where - __A: _serde::de::EnumAccess<'de>, - { - match match _serde::de::EnumAccess::variant(__data) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - (__Field::__field0, __variant) => { - match _serde::de::VariantAccess::unit_variant(__variant) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::export::Ok(DeEnum::Unit) - } - (__Field::__field1, __variant) => { - struct __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, B, C, D> _serde::de::Visitor<'de> for __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - type Value = DeEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple variant DeEnum::Seq", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - i8, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 0usize, - &"tuple variant DeEnum::Seq with 4 elements", - ), - ); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - B, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 1usize, - &"tuple variant DeEnum::Seq with 4 elements", - ), - ); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::< - C, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 2usize, - &"tuple variant DeEnum::Seq with 4 elements", - ), - ); - } - }; - let __field3 = match match _serde::de::SeqAccess::next_element::< - D, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 3usize, - &"tuple variant DeEnum::Seq with 4 elements", - ), - ); - } - }; - _serde::export::Ok(DeEnum::Seq( - __field0, __field1, __field2, __field3, - )) - } - } - _serde::de::VariantAccess::tuple_variant( - __variant, - 4usize, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - (__Field::__field2, __variant) => { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __field3, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "field identifier", - ) - } - fn visit_u64<__E>( - self, - __value: u64, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - 3u64 => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 4", - )), - } - } - fn visit_str<__E>( - self, - __value: &str, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - "b" => _serde::export::Ok(__Field::__field1), - "c" => _serde::export::Ok(__Field::__field2), - "d" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - b"b" => _serde::export::Ok(__Field::__field1), - b"c" => _serde::export::Ok(__Field::__field2), - b"d" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>( - __deserializer: __D, - ) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier( - __deserializer, - __FieldVisitor, - ) - } - } - struct __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, B, C, D> _serde::de::Visitor<'de> for __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - type Value = DeEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "struct variant DeEnum::Map", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - i8, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 0usize, - &"struct variant DeEnum::Map with 4 elements", - ), - ); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - B, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 1usize, - &"struct variant DeEnum::Map with 4 elements", - ), - ); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::< - C, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 2usize, - &"struct variant DeEnum::Map with 4 elements", - ), - ); - } - }; - let __field3 = match match _serde::de::SeqAccess::next_element::< - D, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 3usize, - &"struct variant DeEnum::Map with 4 elements", - ), - ); - } - }; - _serde::export::Ok(DeEnum::Map { - a: __field0, - b: __field1, - c: __field2, - d: __field3, - }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = - _serde::export::None; - let mut __field1: _serde::export::Option = - _serde::export::None; - let mut __field2: _serde::export::Option = - _serde::export::None; - let mut __field3: _serde::export::Option = - _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "a" ) ) ; - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field1 => { - if _serde::export::Option::is_some(&__field1) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "b" ) ) ; - } - __field1 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field2 => { - if _serde::export::Option::is_some(&__field2) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "c" ) ) ; - } - __field2 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field3 => { - if _serde::export::Option::is_some(&__field3) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "d" ) ) ; - } - __field3 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >( - &mut __map - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => { - match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field1 = match __field1 { - _serde::export::Some(__field1) => __field1, - _serde::export::None => { - match _serde::private::de::missing_field("b") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field2 = match __field2 { - _serde::export::Some(__field2) => __field2, - _serde::export::None => { - match _serde::private::de::missing_field("c") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field3 = match __field3 { - _serde::export::Some(__field3) => __field3, - _serde::export::None => { - match _serde::private::de::missing_field("d") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - _serde::export::Ok(DeEnum::Map { - a: __field0, - b: __field1, - c: __field2, - d: __field3, - }) - } - } - const FIELDS: &'static [&'static str] = &["a", "b", "c", "d"]; - _serde::de::VariantAccess::struct_variant( - __variant, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - (__Field::__field3, __variant) => { - match _serde::de::VariantAccess::unit_variant(__variant) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::export::Ok(DeEnum::_Unit2) - } - (__Field::__field4, __variant) => { - struct __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, B, C, D> _serde::de::Visitor<'de> for __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - type Value = DeEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple variant DeEnum::_Seq2", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - i8, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 0usize, - &"tuple variant DeEnum::_Seq2 with 4 elements", - ), - ); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - B, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 1usize, - &"tuple variant DeEnum::_Seq2 with 4 elements", - ), - ); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::< - C, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 2usize, - &"tuple variant DeEnum::_Seq2 with 4 elements", - ), - ); - } - }; - let __field3 = match match _serde::de::SeqAccess::next_element::< - D, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 3usize, - &"tuple variant DeEnum::_Seq2 with 4 elements", - ), - ); - } - }; - _serde::export::Ok(DeEnum::_Seq2( - __field0, __field1, __field2, __field3, - )) - } - } - _serde::de::VariantAccess::tuple_variant( - __variant, - 4usize, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - (__Field::__field5, __variant) => { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __field3, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "field identifier", - ) - } - fn visit_u64<__E>( - self, - __value: u64, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - 3u64 => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 4", - )), - } - } - fn visit_str<__E>( - self, - __value: &str, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - "b" => _serde::export::Ok(__Field::__field1), - "c" => _serde::export::Ok(__Field::__field2), - "d" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - b"b" => _serde::export::Ok(__Field::__field1), - b"c" => _serde::export::Ok(__Field::__field2), - b"d" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>( - __deserializer: __D, - ) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier( - __deserializer, - __FieldVisitor, - ) - } - } - struct __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, B, C, D> _serde::de::Visitor<'de> for __Visitor<'de, B, C, D> - where - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - D: _serde::Deserialize<'de>, - { - type Value = DeEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "struct variant DeEnum::_Map2", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - i8, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 0usize, - &"struct variant DeEnum::_Map2 with 4 elements", - ), - ); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - B, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 1usize, - &"struct variant DeEnum::_Map2 with 4 elements", - ), - ); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::< - C, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 2usize, - &"struct variant DeEnum::_Map2 with 4 elements", - ), - ); - } - }; - let __field3 = match match _serde::de::SeqAccess::next_element::< - D, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err( - _serde::de::Error::invalid_length( - 3usize, - &"struct variant DeEnum::_Map2 with 4 elements", - ), - ); - } - }; - _serde::export::Ok(DeEnum::_Map2 { - a: __field0, - b: __field1, - c: __field2, - d: __field3, - }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = - _serde::export::None; - let mut __field1: _serde::export::Option = - _serde::export::None; - let mut __field2: _serde::export::Option = - _serde::export::None; - let mut __field3: _serde::export::Option = - _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "a" ) ) ; - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field1 => { - if _serde::export::Option::is_some(&__field1) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "b" ) ) ; - } - __field1 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field2 => { - if _serde::export::Option::is_some(&__field2) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "c" ) ) ; - } - __field2 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field3 => { - if _serde::export::Option::is_some(&__field3) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "d" ) ) ; - } - __field3 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >( - &mut __map - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => { - match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field1 = match __field1 { - _serde::export::Some(__field1) => __field1, - _serde::export::None => { - match _serde::private::de::missing_field("b") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field2 = match __field2 { - _serde::export::Some(__field2) => __field2, - _serde::export::None => { - match _serde::private::de::missing_field("c") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field3 = match __field3 { - _serde::export::Some(__field3) => __field3, - _serde::export::None => { - match _serde::private::de::missing_field("d") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - _serde::export::Ok(DeEnum::_Map2 { - a: __field0, - b: __field1, - c: __field2, - d: __field3, - }) - } - } - const FIELDS: &'static [&'static str] = &["a", "b", "c", "d"]; - _serde::de::VariantAccess::struct_variant( - __variant, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } - } - } - const VARIANTS: &'static [&'static str] = - &["Unit", "Seq", "Map", "_Unit2", "_Seq2", "_Map2"]; - _serde::Deserializer::deserialize_enum( - __deserializer, - "DeEnum", - VARIANTS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/de_enum.rs b/test_suite/tests/expand/de_enum.rs deleted file mode 100644 index ac0c49b57..000000000 --- a/test_suite/tests/expand/de_enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -enum DeEnum { - Unit, - Seq(i8, B, C, D), - Map { a: i8, b: B, c: C, d: D }, - - // Make sure we can support more than one variant. - _Unit2, - _Seq2(i8, B, C, D), - _Map2 { a: i8, b: B, c: C, d: D }, -} diff --git a/test_suite/tests/expand/default_ty_param.expanded.rs b/test_suite/tests/expand/default_ty_param.expanded.rs deleted file mode 100644 index 8aaa3ab43..000000000 --- a/test_suite/tests/expand/default_ty_param.expanded.rs +++ /dev/null @@ -1,401 +0,0 @@ -use serde::{Deserialize, Serialize}; -trait AssociatedType { - type X; -} -impl AssociatedType for i32 { - type X = i32; -} -struct DefaultTyParam = i32> { - phantom: PhantomData, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl> _serde::Serialize for DefaultTyParam { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - let mut __serde_state = match _serde::Serializer::serialize_struct( - __serializer, - "DefaultTyParam", - false as usize + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStruct::serialize_field( - &mut __serde_state, - "phantom", - &self.phantom, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStruct::end(__serde_state) - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, T: AssociatedType> _serde::Deserialize<'de> for DefaultTyParam { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "phantom" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"phantom" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, T: AssociatedType> { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T: AssociatedType> _serde::de::Visitor<'de> for __Visitor<'de, T> { - type Value = DefaultTyParam; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct DefaultTyParam") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::>( - &mut __seq, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct DefaultTyParam with 1 element", - )); - } - }; - _serde::export::Ok(DefaultTyParam { phantom: __field0 }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option> = _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field( - "phantom", - ), - ); - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::>( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => match _serde::private::de::missing_field("phantom") - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - }; - _serde::export::Ok(DefaultTyParam { phantom: __field0 }) - } - } - const FIELDS: &'static [&'static str] = &["phantom"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "DefaultTyParam", - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "phantom" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"phantom" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, 'place, T: AssociatedType + 'place> { - place: &'place mut DefaultTyParam, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, T: AssociatedType + 'place> _serde::de::Visitor<'de> - for __Visitor<'de, 'place, T> - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct DefaultTyParam") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.phantom), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct DefaultTyParam with 1 element", - )); - } - _serde::export::Ok(()) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: bool = false; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if __field0 { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field( - "phantom", - ), - ); - } - match _serde::de::MapAccess::next_value_seed( - &mut __map, - _serde::private::de::InPlaceSeed(&mut self.place.phantom), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - __field0 = true; - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - if !__field0 { - self.place.phantom = match _serde::private::de::missing_field("phantom") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }; - _serde::export::Ok(()) - } - } - const FIELDS: &'static [&'static str] = &["phantom"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "DefaultTyParam", - FIELDS, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/default_ty_param.rs b/test_suite/tests/expand/default_ty_param.rs deleted file mode 100644 index 86ae9dd36..000000000 --- a/test_suite/tests/expand/default_ty_param.rs +++ /dev/null @@ -1,14 +0,0 @@ -use serde::{Deserialize, Serialize}; - -trait AssociatedType { - type X; -} - -impl AssociatedType for i32 { - type X = i32; -} - -#[derive(Serialize, Deserialize)] -struct DefaultTyParam = i32> { - phantom: PhantomData, -} diff --git a/test_suite/tests/expand/generic_enum.expanded.rs b/test_suite/tests/expand/generic_enum.expanded.rs deleted file mode 100644 index add7c510d..000000000 --- a/test_suite/tests/expand/generic_enum.expanded.rs +++ /dev/null @@ -1,582 +0,0 @@ -use serde::{Deserialize, Serialize}; -pub enum GenericEnum { - Unit, - NewType(T), - Seq(T, U), - Map { x: T, y: U }, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for GenericEnum - where - T: _serde::Serialize, - U: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - match *self { - GenericEnum::Unit => _serde::Serializer::serialize_unit_variant( - __serializer, - "GenericEnum", - 0u32, - "Unit", - ), - GenericEnum::NewType(ref __field0) => { - _serde::Serializer::serialize_newtype_variant( - __serializer, - "GenericEnum", - 1u32, - "NewType", - __field0, - ) - } - GenericEnum::Seq(ref __field0, ref __field1) => { - let mut __serde_state = match _serde::Serializer::serialize_tuple_variant( - __serializer, - "GenericEnum", - 2u32, - "Seq", - 0 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field0, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleVariant::end(__serde_state) - } - GenericEnum::Map { ref x, ref y } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "GenericEnum", - 3u32, - "Map", - 0 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "x", - x, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "y", - y, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - } - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, T, U> _serde::Deserialize<'de> for GenericEnum - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __field3, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "variant identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - 3u64 => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"variant index 0 <= i < 4", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "Unit" => _serde::export::Ok(__Field::__field0), - "NewType" => _serde::export::Ok(__Field::__field1), - "Seq" => _serde::export::Ok(__Field::__field2), - "Map" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"Unit" => _serde::export::Ok(__Field::__field0), - b"NewType" => _serde::export::Ok(__Field::__field1), - b"Seq" => _serde::export::Ok(__Field::__field2), - b"Map" => _serde::export::Ok(__Field::__field3), - _ => { - let __value = &_serde::export::from_utf8_lossy(__value); - _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )) - } - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T, U> _serde::de::Visitor<'de> for __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - type Value = GenericEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "enum GenericEnum") - } - fn visit_enum<__A>( - self, - __data: __A, - ) -> _serde::export::Result - where - __A: _serde::de::EnumAccess<'de>, - { - match match _serde::de::EnumAccess::variant(__data) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - (__Field::__field0, __variant) => { - match _serde::de::VariantAccess::unit_variant(__variant) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::export::Ok(GenericEnum::Unit) - } - (__Field::__field1, __variant) => _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::(__variant), - GenericEnum::NewType, - ), - (__Field::__field2, __variant) => { - struct __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T, U> _serde::de::Visitor<'de> for __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - type Value = GenericEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple variant GenericEnum::Seq", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - T, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 0usize , & "tuple variant GenericEnum::Seq with 2 elements" ) ) ; - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - U, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 1usize , & "tuple variant GenericEnum::Seq with 2 elements" ) ) ; - } - }; - _serde::export::Ok(GenericEnum::Seq(__field0, __field1)) - } - } - _serde::de::VariantAccess::tuple_variant( - __variant, - 2usize, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - (__Field::__field3, __variant) => { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "field identifier", - ) - } - fn visit_u64<__E>( - self, - __value: u64, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 2", - )), - } - } - fn visit_str<__E>( - self, - __value: &str, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "x" => _serde::export::Ok(__Field::__field0), - "y" => _serde::export::Ok(__Field::__field1), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"x" => _serde::export::Ok(__Field::__field0), - b"y" => _serde::export::Ok(__Field::__field1), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>( - __deserializer: __D, - ) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier( - __deserializer, - __FieldVisitor, - ) - } - } - struct __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T, U> _serde::de::Visitor<'de> for __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - type Value = GenericEnum; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "struct variant GenericEnum::Map", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - T, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 0usize , & "struct variant GenericEnum::Map with 2 elements" ) ) ; - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::< - U, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 1usize , & "struct variant GenericEnum::Map with 2 elements" ) ) ; - } - }; - _serde::export::Ok(GenericEnum::Map { - x: __field0, - y: __field1, - }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = - _serde::export::None; - let mut __field1: _serde::export::Option = - _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "x" ) ) ; - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field1 => { - if _serde::export::Option::is_some(&__field1) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "y" ) ) ; - } - __field1 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >( - &mut __map - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => { - match _serde::private::de::missing_field("x") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - let __field1 = match __field1 { - _serde::export::Some(__field1) => __field1, - _serde::export::None => { - match _serde::private::de::missing_field("y") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - _serde::export::Ok(GenericEnum::Map { - x: __field0, - y: __field1, - }) - } - } - const FIELDS: &'static [&'static str] = &["x", "y"]; - _serde::de::VariantAccess::struct_variant( - __variant, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } - } - } - const VARIANTS: &'static [&'static str] = &["Unit", "NewType", "Seq", "Map"]; - _serde::Deserializer::deserialize_enum( - __deserializer, - "GenericEnum", - VARIANTS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/generic_enum.rs b/test_suite/tests/expand/generic_enum.rs deleted file mode 100644 index 400a50880..000000000 --- a/test_suite/tests/expand/generic_enum.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -pub enum GenericEnum { - Unit, - NewType(T), - Seq(T, U), - Map { x: T, y: U }, -} diff --git a/test_suite/tests/expand/generic_struct.expanded.rs b/test_suite/tests/expand/generic_struct.expanded.rs deleted file mode 100644 index 59d2e51d7..000000000 --- a/test_suite/tests/expand/generic_struct.expanded.rs +++ /dev/null @@ -1,582 +0,0 @@ -use serde::{Deserialize, Serialize}; -pub struct GenericStruct { - x: T, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for GenericStruct - where - T: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - let mut __serde_state = match _serde::Serializer::serialize_struct( - __serializer, - "GenericStruct", - false as usize + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, "x", &self.x) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStruct::end(__serde_state) - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, T> _serde::Deserialize<'de> for GenericStruct - where - T: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "x" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"x" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, T> - where - T: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T> _serde::de::Visitor<'de> for __Visitor<'de, T> - where - T: _serde::Deserialize<'de>, - { - type Value = GenericStruct; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct GenericStruct") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct GenericStruct with 1 element", - )); - } - }; - _serde::export::Ok(GenericStruct { x: __field0 }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("x"), - ); - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => match _serde::private::de::missing_field("x") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - }; - _serde::export::Ok(GenericStruct { x: __field0 }) - } - } - const FIELDS: &'static [&'static str] = &["x"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "GenericStruct", - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "x" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"x" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, 'place, T: 'place> - where - T: _serde::Deserialize<'de>, - { - place: &'place mut GenericStruct, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, T: 'place> _serde::de::Visitor<'de> for __Visitor<'de, 'place, T> - where - T: _serde::Deserialize<'de>, - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct GenericStruct") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.x), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct GenericStruct with 1 element", - )); - } - _serde::export::Ok(()) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: bool = false; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if __field0 { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("x"), - ); - } - match _serde::de::MapAccess::next_value_seed( - &mut __map, - _serde::private::de::InPlaceSeed(&mut self.place.x), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - __field0 = true; - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - if !__field0 { - self.place.x = match _serde::private::de::missing_field("x") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }; - _serde::export::Ok(()) - } - } - const FIELDS: &'static [&'static str] = &["x"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "GenericStruct", - FIELDS, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; -pub struct GenericNewTypeStruct(T); -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for GenericNewTypeStruct - where - T: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - _serde::Serializer::serialize_newtype_struct( - __serializer, - "GenericNewTypeStruct", - &self.0, - ) - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, T> _serde::Deserialize<'de> for GenericNewTypeStruct - where - T: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, T> - where - T: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T> _serde::de::Visitor<'de> for __Visitor<'de, T> - where - T: _serde::Deserialize<'de>, - { - type Value = GenericNewTypeStruct; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple struct GenericNewTypeStruct", - ) - } - #[inline] - fn visit_newtype_struct<__E>( - self, - __e: __E, - ) -> _serde::export::Result - where - __E: _serde::Deserializer<'de>, - { - let __field0: T = match ::deserialize(__e) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::export::Ok(GenericNewTypeStruct(__field0)) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct GenericNewTypeStruct with 1 element", - )); - } - }; - _serde::export::Ok(GenericNewTypeStruct(__field0)) - } - } - _serde::Deserializer::deserialize_newtype_struct( - __deserializer, - "GenericNewTypeStruct", - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, 'place, T: 'place> - where - T: _serde::Deserialize<'de>, - { - place: &'place mut GenericNewTypeStruct, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, T: 'place> _serde::de::Visitor<'de> for __Visitor<'de, 'place, T> - where - T: _serde::Deserialize<'de>, - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple struct GenericNewTypeStruct", - ) - } - #[inline] - fn visit_newtype_struct<__E>( - self, - __e: __E, - ) -> _serde::export::Result - where - __E: _serde::Deserializer<'de>, - { - _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.0), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct GenericNewTypeStruct with 1 element", - )); - } - _serde::export::Ok(()) - } - } - _serde::Deserializer::deserialize_newtype_struct( - __deserializer, - "GenericNewTypeStruct", - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/generic_struct.rs b/test_suite/tests/expand/generic_struct.rs deleted file mode 100644 index 650cb977d..000000000 --- a/test_suite/tests/expand/generic_struct.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -pub struct GenericStruct { - x: T, -} - -#[derive(Serialize, Deserialize)] -pub struct GenericNewTypeStruct(T); diff --git a/test_suite/tests/expand/generic_tuple_struct.expanded.rs b/test_suite/tests/expand/generic_tuple_struct.expanded.rs deleted file mode 100644 index 8eaf0e7ef..000000000 --- a/test_suite/tests/expand/generic_tuple_struct.expanded.rs +++ /dev/null @@ -1,172 +0,0 @@ -use serde::{Deserialize, Serialize}; -pub struct GenericTupleStruct(T, U); -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, T, U> _serde::Deserialize<'de> for GenericTupleStruct - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, T, U> _serde::de::Visitor<'de> for __Visitor<'de, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - type Value = GenericTupleStruct; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple struct GenericTupleStruct", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct GenericTupleStruct with 2 elements", - )); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"tuple struct GenericTupleStruct with 2 elements", - )); - } - }; - _serde::export::Ok(GenericTupleStruct(__field0, __field1)) - } - } - _serde::Deserializer::deserialize_tuple_struct( - __deserializer, - "GenericTupleStruct", - 2usize, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, 'place, T: 'place, U: 'place> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - place: &'place mut GenericTupleStruct, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, T: 'place, U: 'place> _serde::de::Visitor<'de> for __Visitor<'de, 'place, T, U> - where - T: _serde::Deserialize<'de>, - U: _serde::Deserialize<'de>, - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "tuple struct GenericTupleStruct", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.0), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct GenericTupleStruct with 2 elements", - )); - } - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.1), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"tuple struct GenericTupleStruct with 2 elements", - )); - } - _serde::export::Ok(()) - } - } - _serde::Deserializer::deserialize_tuple_struct( - __deserializer, - "GenericTupleStruct", - 2usize, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/generic_tuple_struct.rs b/test_suite/tests/expand/generic_tuple_struct.rs deleted file mode 100644 index 90721db61..000000000 --- a/test_suite/tests/expand/generic_tuple_struct.rs +++ /dev/null @@ -1,4 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Deserialize)] -pub struct GenericTupleStruct(T, U); diff --git a/test_suite/tests/expand/lifetimes.expanded.rs b/test_suite/tests/expand/lifetimes.expanded.rs deleted file mode 100644 index 9840d4401..000000000 --- a/test_suite/tests/expand/lifetimes.expanded.rs +++ /dev/null @@ -1,601 +0,0 @@ -use serde::{Deserialize, Serialize}; -enum Lifetimes<'a> { - LifetimeSeq(&'a i32), - NoLifetimeSeq(i32), - LifetimeMap { a: &'a i32 }, - NoLifetimeMap { a: i32 }, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'a> _serde::Serialize for Lifetimes<'a> { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - match *self { - Lifetimes::LifetimeSeq(ref __field0) => { - _serde::Serializer::serialize_newtype_variant( - __serializer, - "Lifetimes", - 0u32, - "LifetimeSeq", - __field0, - ) - } - Lifetimes::NoLifetimeSeq(ref __field0) => { - _serde::Serializer::serialize_newtype_variant( - __serializer, - "Lifetimes", - 1u32, - "NoLifetimeSeq", - __field0, - ) - } - Lifetimes::LifetimeMap { ref a } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "Lifetimes", - 2u32, - "LifetimeMap", - 0 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - Lifetimes::NoLifetimeMap { ref a } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "Lifetimes", - 3u32, - "NoLifetimeMap", - 0 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - } - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, 'a> _serde::Deserialize<'de> for Lifetimes<'a> { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __field3, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "variant identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - 3u64 => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"variant index 0 <= i < 4", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "LifetimeSeq" => _serde::export::Ok(__Field::__field0), - "NoLifetimeSeq" => _serde::export::Ok(__Field::__field1), - "LifetimeMap" => _serde::export::Ok(__Field::__field2), - "NoLifetimeMap" => _serde::export::Ok(__Field::__field3), - _ => _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"LifetimeSeq" => _serde::export::Ok(__Field::__field0), - b"NoLifetimeSeq" => _serde::export::Ok(__Field::__field1), - b"LifetimeMap" => _serde::export::Ok(__Field::__field2), - b"NoLifetimeMap" => _serde::export::Ok(__Field::__field3), - _ => { - let __value = &_serde::export::from_utf8_lossy(__value); - _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )) - } - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, 'a> { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'a> _serde::de::Visitor<'de> for __Visitor<'de, 'a> { - type Value = Lifetimes<'a>; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "enum Lifetimes") - } - fn visit_enum<__A>( - self, - __data: __A, - ) -> _serde::export::Result - where - __A: _serde::de::EnumAccess<'de>, - { - match match _serde::de::EnumAccess::variant(__data) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - (__Field::__field0, __variant) => _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<&'a i32>(__variant), - Lifetimes::LifetimeSeq, - ), - (__Field::__field1, __variant) => _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::(__variant), - Lifetimes::NoLifetimeSeq, - ), - (__Field::__field2, __variant) => { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "field identifier", - ) - } - fn visit_u64<__E>( - self, - __value: u64, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>( - self, - __value: &str, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>( - __deserializer: __D, - ) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier( - __deserializer, - __FieldVisitor, - ) - } - } - struct __Visitor<'de, 'a> { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'a> _serde::de::Visitor<'de> for __Visitor<'de, 'a> { - type Value = Lifetimes<'a>; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "struct variant Lifetimes::LifetimeMap", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - &'a i32, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 0usize , & "struct variant Lifetimes::LifetimeMap with 1 element" ) ) ; - } - }; - _serde::export::Ok(Lifetimes::LifetimeMap { a: __field0 }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option<&'a i32> = - _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "a" ) ) ; - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::<&'a i32>( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >( - &mut __map - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => { - match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - _serde::export::Ok(Lifetimes::LifetimeMap { a: __field0 }) - } - } - const FIELDS: &'static [&'static str] = &["a"]; - _serde::de::VariantAccess::struct_variant( - __variant, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - (__Field::__field3, __variant) => { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "field identifier", - ) - } - fn visit_u64<__E>( - self, - __value: u64, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), - } - } - fn visit_str<__E>( - self, - __value: &str, - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>( - __deserializer: __D, - ) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier( - __deserializer, - __FieldVisitor, - ) - } - } - struct __Visitor<'de, 'a> { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'a> _serde::de::Visitor<'de> for __Visitor<'de, 'a> { - type Value = Lifetimes<'a>; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str( - __formatter, - "struct variant Lifetimes::NoLifetimeMap", - ) - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::< - i32, - >( - &mut __seq - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde :: export :: Err ( _serde :: de :: Error :: invalid_length ( 0usize , & "struct variant Lifetimes::NoLifetimeMap with 1 element" ) ) ; - } - }; - _serde::export::Ok(Lifetimes::NoLifetimeMap { a: __field0 }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = - _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde :: export :: Err ( < __A :: Error as _serde :: de :: Error > :: duplicate_field ( "a" ) ) ; - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::( - &mut __map, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >( - &mut __map - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => { - match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - } - }; - _serde::export::Ok(Lifetimes::NoLifetimeMap { a: __field0 }) - } - } - const FIELDS: &'static [&'static str] = &["a"]; - _serde::de::VariantAccess::struct_variant( - __variant, - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } - } - } - const VARIANTS: &'static [&'static str] = &[ - "LifetimeSeq", - "NoLifetimeSeq", - "LifetimeMap", - "NoLifetimeMap", - ]; - _serde::Deserializer::deserialize_enum( - __deserializer, - "Lifetimes", - VARIANTS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/lifetimes.rs b/test_suite/tests/expand/lifetimes.rs deleted file mode 100644 index 0e8996737..000000000 --- a/test_suite/tests/expand/lifetimes.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -enum Lifetimes<'a> { - LifetimeSeq(&'a i32), - NoLifetimeSeq(i32), - LifetimeMap { a: &'a i32 }, - NoLifetimeMap { a: i32 }, -} diff --git a/test_suite/tests/expand/named_map.expanded.rs b/test_suite/tests/expand/named_map.expanded.rs deleted file mode 100644 index ce43b6634..000000000 --- a/test_suite/tests/expand/named_map.expanded.rs +++ /dev/null @@ -1,615 +0,0 @@ -use serde::{Deserialize, Serialize}; -struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> { - a: &'a A, - b: &'b mut B, - c: C, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'a, 'b, A: 'a, B: 'b, C> _serde::Serialize for SerNamedMap<'a, 'b, A, B, C> - where - A: _serde::Serialize, - B: _serde::Serialize, - C: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - let mut __serde_state = match _serde::Serializer::serialize_struct( - __serializer, - "SerNamedMap", - false as usize + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, "a", &self.a) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, "b", &self.b) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, "c", &self.c) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStruct::end(__serde_state) - } - } -}; -struct DeNamedMap { - a: A, - b: B, - c: C, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, A, B, C> _serde::Deserialize<'de> for DeNamedMap - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 3", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - "b" => _serde::export::Ok(__Field::__field1), - "c" => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - b"b" => _serde::export::Ok(__Field::__field1), - b"c" => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, A, B, C> _serde::de::Visitor<'de> for __Visitor<'de, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - type Value = DeNamedMap; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct DeNamedMap") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::
(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct DeNamedMap with 3 elements", - )); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"struct DeNamedMap with 3 elements", - )); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 2usize, - &"struct DeNamedMap with 3 elements", - )); - } - }; - _serde::export::Ok(DeNamedMap { - a: __field0, - b: __field1, - c: __field2, - }) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: _serde::export::Option = _serde::export::None; - let mut __field1: _serde::export::Option = _serde::export::None; - let mut __field2: _serde::export::Option = _serde::export::None; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if _serde::export::Option::is_some(&__field0) { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("a"), - ); - } - __field0 = _serde::export::Some( - match _serde::de::MapAccess::next_value::(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field1 => { - if _serde::export::Option::is_some(&__field1) { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("b"), - ); - } - __field1 = _serde::export::Some( - match _serde::de::MapAccess::next_value::(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - __Field::__field2 => { - if _serde::export::Option::is_some(&__field2) { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("c"), - ); - } - __field2 = _serde::export::Some( - match _serde::de::MapAccess::next_value::(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - ); - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - let __field0 = match __field0 { - _serde::export::Some(__field0) => __field0, - _serde::export::None => match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - }; - let __field1 = match __field1 { - _serde::export::Some(__field1) => __field1, - _serde::export::None => match _serde::private::de::missing_field("b") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - }; - let __field2 = match __field2 { - _serde::export::Some(__field2) => __field2, - _serde::export::None => match _serde::private::de::missing_field("c") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }, - }; - _serde::export::Ok(DeNamedMap { - a: __field0, - b: __field1, - c: __field2, - }) - } - } - const FIELDS: &'static [&'static str] = &["a", "b", "c"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "DeNamedMap", - FIELDS, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field { - __field0, - __field1, - __field2, - __ignore, - } - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "field identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - 0u64 => _serde::export::Ok(__Field::__field0), - 1u64 => _serde::export::Ok(__Field::__field1), - 2u64 => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 3", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - "a" => _serde::export::Ok(__Field::__field0), - "b" => _serde::export::Ok(__Field::__field1), - "c" => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Ok(__Field::__ignore), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - b"a" => _serde::export::Ok(__Field::__field0), - b"b" => _serde::export::Ok(__Field::__field1), - b"c" => _serde::export::Ok(__Field::__field2), - _ => _serde::export::Ok(__Field::__ignore), - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de, 'place, A: 'place, B: 'place, C: 'place> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - place: &'place mut DeNamedMap, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, A: 'place, B: 'place, C: 'place> _serde::de::Visitor<'de> - for __Visitor<'de, 'place, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "struct DeNamedMap") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.a), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"struct DeNamedMap with 3 elements", - )); - } - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.b), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"struct DeNamedMap with 3 elements", - )); - } - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.c), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 2usize, - &"struct DeNamedMap with 3 elements", - )); - } - _serde::export::Ok(()) - } - #[inline] - fn visit_map<__A>( - self, - mut __map: __A, - ) -> _serde::export::Result - where - __A: _serde::de::MapAccess<'de>, - { - let mut __field0: bool = false; - let mut __field1: bool = false; - let mut __field2: bool = false; - while let _serde::export::Some(__key) = - match _serde::de::MapAccess::next_key::<__Field>(&mut __map) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } - { - match __key { - __Field::__field0 => { - if __field0 { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("a"), - ); - } - match _serde::de::MapAccess::next_value_seed( - &mut __map, - _serde::private::de::InPlaceSeed(&mut self.place.a), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - __field0 = true; - } - __Field::__field1 => { - if __field1 { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("b"), - ); - } - match _serde::de::MapAccess::next_value_seed( - &mut __map, - _serde::private::de::InPlaceSeed(&mut self.place.b), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - __field1 = true; - } - __Field::__field2 => { - if __field2 { - return _serde::export::Err( - <__A::Error as _serde::de::Error>::duplicate_field("c"), - ); - } - match _serde::de::MapAccess::next_value_seed( - &mut __map, - _serde::private::de::InPlaceSeed(&mut self.place.c), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - __field2 = true; - } - _ => { - let _ = match _serde::de::MapAccess::next_value::< - _serde::de::IgnoredAny, - >(&mut __map) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - } - } - } - if !__field0 { - self.place.a = match _serde::private::de::missing_field("a") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }; - if !__field1 { - self.place.b = match _serde::private::de::missing_field("b") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }; - if !__field2 { - self.place.c = match _serde::private::de::missing_field("c") { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - }; - _serde::export::Ok(()) - } - } - const FIELDS: &'static [&'static str] = &["a", "b", "c"]; - _serde::Deserializer::deserialize_struct( - __deserializer, - "DeNamedMap", - FIELDS, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/named_map.rs b/test_suite/tests/expand/named_map.rs deleted file mode 100644 index 367e9b528..000000000 --- a/test_suite/tests/expand/named_map.rs +++ /dev/null @@ -1,15 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize)] -struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> { - a: &'a A, - b: &'b mut B, - c: C, -} - -#[derive(Deserialize)] -struct DeNamedMap { - a: A, - b: B, - c: C, -} diff --git a/test_suite/tests/expand/named_tuple.expanded.rs b/test_suite/tests/expand/named_tuple.expanded.rs deleted file mode 100644 index 8b5e4eee0..000000000 --- a/test_suite/tests/expand/named_tuple.expanded.rs +++ /dev/null @@ -1,250 +0,0 @@ -use serde::{Deserialize, Serialize}; -struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C); -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'a, 'b, A: 'a, B: 'b, C> _serde::Serialize for SerNamedTuple<'a, 'b, A, B, C> - where - A: _serde::Serialize, - B: _serde::Serialize, - C: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - let mut __serde_state = match _serde::Serializer::serialize_tuple_struct( - __serializer, - "SerNamedTuple", - 0 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleStruct::serialize_field(&mut __serde_state, &self.0) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleStruct::serialize_field(&mut __serde_state, &self.1) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleStruct::serialize_field(&mut __serde_state, &self.2) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleStruct::end(__serde_state) - } - } -}; -struct DeNamedTuple(A, B, C); -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de, A, B, C> _serde::Deserialize<'de> for DeNamedTuple - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - marker: _serde::export::PhantomData>, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, A, B, C> _serde::de::Visitor<'de> for __Visitor<'de, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - type Value = DeNamedTuple; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "tuple struct DeNamedTuple") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - let __field0 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - }; - let __field1 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - }; - let __field2 = match match _serde::de::SeqAccess::next_element::(&mut __seq) - { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - _serde::export::Some(__value) => __value, - _serde::export::None => { - return _serde::export::Err(_serde::de::Error::invalid_length( - 2usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - }; - _serde::export::Ok(DeNamedTuple(__field0, __field1, __field2)) - } - } - _serde::Deserializer::deserialize_tuple_struct( - __deserializer, - "DeNamedTuple", - 3usize, - __Visitor { - marker: _serde::export::PhantomData::>, - lifetime: _serde::export::PhantomData, - }, - ) - } - fn deserialize_in_place<__D>( - __deserializer: __D, - __place: &mut Self, - ) -> _serde::export::Result<(), __D::Error> - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor<'de, 'place, A: 'place, B: 'place, C: 'place> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - place: &'place mut DeNamedTuple, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de, 'place, A: 'place, B: 'place, C: 'place> _serde::de::Visitor<'de> - for __Visitor<'de, 'place, A, B, C> - where - A: _serde::Deserialize<'de>, - B: _serde::Deserialize<'de>, - C: _serde::Deserialize<'de>, - { - type Value = (); - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "tuple struct DeNamedTuple") - } - #[inline] - fn visit_seq<__A>( - self, - mut __seq: __A, - ) -> _serde::export::Result - where - __A: _serde::de::SeqAccess<'de>, - { - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.0), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 0usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.1), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 1usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - if let _serde::export::None = match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - _serde::private::de::InPlaceSeed(&mut self.place.2), - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - } { - return _serde::export::Err(_serde::de::Error::invalid_length( - 2usize, - &"tuple struct DeNamedTuple with 3 elements", - )); - } - _serde::export::Ok(()) - } - } - _serde::Deserializer::deserialize_tuple_struct( - __deserializer, - "DeNamedTuple", - 3usize, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/named_tuple.rs b/test_suite/tests/expand/named_tuple.rs deleted file mode 100644 index b9e8847dd..000000000 --- a/test_suite/tests/expand/named_tuple.rs +++ /dev/null @@ -1,7 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize)] -struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C); - -#[derive(Deserialize)] -struct DeNamedTuple(A, B, C); diff --git a/test_suite/tests/expand/named_unit.expanded.rs b/test_suite/tests/expand/named_unit.expanded.rs deleted file mode 100644 index dfe44ddd0..000000000 --- a/test_suite/tests/expand/named_unit.expanded.rs +++ /dev/null @@ -1,49 +0,0 @@ -use serde::{Deserialize, Serialize}; -struct NamedUnit; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for NamedUnit { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - _serde::Serializer::serialize_unit_struct(__serializer, "NamedUnit") - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de> _serde::Deserialize<'de> for NamedUnit { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - struct __Visitor; - impl<'de> _serde::de::Visitor<'de> for __Visitor { - type Value = NamedUnit; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "unit struct NamedUnit") - } - #[inline] - fn visit_unit<__E>(self) -> _serde::export::Result - where - __E: _serde::de::Error, - { - _serde::export::Ok(NamedUnit) - } - } - _serde::Deserializer::deserialize_unit_struct(__deserializer, "NamedUnit", __Visitor) - } - } -}; diff --git a/test_suite/tests/expand/named_unit.rs b/test_suite/tests/expand/named_unit.rs deleted file mode 100644 index 35d71bf93..000000000 --- a/test_suite/tests/expand/named_unit.rs +++ /dev/null @@ -1,4 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -struct NamedUnit; diff --git a/test_suite/tests/expand/ser_enum.expanded.rs b/test_suite/tests/expand/ser_enum.expanded.rs deleted file mode 100644 index 3f4db97d9..000000000 --- a/test_suite/tests/expand/ser_enum.expanded.rs +++ /dev/null @@ -1,268 +0,0 @@ -use serde::Serialize; -enum SerEnum<'a, B: 'a, C: 'a, D> -where - D: 'a, -{ - Unit, - Seq(i8, B, &'a C, &'a mut D), - Map { a: i8, b: B, c: &'a C, d: &'a mut D }, - _Unit2, - _Seq2(i8, B, &'a C, &'a mut D), - _Map2 { a: i8, b: B, c: &'a C, d: &'a mut D }, -} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'a, B: 'a, C: 'a, D> _serde::Serialize for SerEnum<'a, B, C, D> - where - D: 'a, - B: _serde::Serialize, - C: _serde::Serialize, - D: _serde::Serialize, - { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - match *self { - SerEnum::Unit => _serde::Serializer::serialize_unit_variant( - __serializer, - "SerEnum", - 0u32, - "Unit", - ), - SerEnum::Seq(ref __field0, ref __field1, ref __field2, ref __field3) => { - let mut __serde_state = match _serde::Serializer::serialize_tuple_variant( - __serializer, - "SerEnum", - 1u32, - "Seq", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field0, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field2, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field3, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleVariant::end(__serde_state) - } - SerEnum::Map { - ref a, - ref b, - ref c, - ref d, - } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "SerEnum", - 2u32, - "Map", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "b", - b, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "c", - c, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "d", - d, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - SerEnum::_Unit2 => _serde::Serializer::serialize_unit_variant( - __serializer, - "SerEnum", - 3u32, - "_Unit2", - ), - SerEnum::_Seq2(ref __field0, ref __field1, ref __field2, ref __field3) => { - let mut __serde_state = match _serde::Serializer::serialize_tuple_variant( - __serializer, - "SerEnum", - 4u32, - "_Seq2", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field0, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field2, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeTupleVariant::serialize_field( - &mut __serde_state, - __field3, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeTupleVariant::end(__serde_state) - } - SerEnum::_Map2 { - ref a, - ref b, - ref c, - ref d, - } => { - let mut __serde_state = match _serde::Serializer::serialize_struct_variant( - __serializer, - "SerEnum", - 5u32, - "_Map2", - 0 + 1 + 1 + 1 + 1, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "a", - a, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "b", - b, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "c", - c, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - match _serde::ser::SerializeStructVariant::serialize_field( - &mut __serde_state, - "d", - d, - ) { - _serde::export::Ok(__val) => __val, - _serde::export::Err(__err) => { - return _serde::export::Err(__err); - } - }; - _serde::ser::SerializeStructVariant::end(__serde_state) - } - } - } - } -}; diff --git a/test_suite/tests/expand/ser_enum.rs b/test_suite/tests/expand/ser_enum.rs deleted file mode 100644 index 15c97a23e..000000000 --- a/test_suite/tests/expand/ser_enum.rs +++ /dev/null @@ -1,16 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -enum SerEnum<'a, B: 'a, C: 'a, D> -where - D: 'a, -{ - Unit, - Seq(i8, B, &'a C, &'a mut D), - Map { a: i8, b: B, c: &'a C, d: &'a mut D }, - - // Make sure we can support more than one variant. - _Unit2, - _Seq2(i8, B, &'a C, &'a mut D), - _Map2 { a: i8, b: B, c: &'a C, d: &'a mut D }, -} diff --git a/test_suite/tests/expand/void.expanded.rs b/test_suite/tests/expand/void.expanded.rs deleted file mode 100644 index fb98c321a..000000000 --- a/test_suite/tests/expand/void.expanded.rs +++ /dev/null @@ -1,124 +0,0 @@ -use serde::{Deserialize, Serialize}; -enum Void {} -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl _serde::Serialize for Void { - fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> - where - __S: _serde::Serializer, - { - match *self {} - } - } -}; -#[doc(hidden)] -#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] -const _: () = { - #[allow(rust_2018_idioms, clippy::useless_attribute)] - extern crate serde as _serde; - #[automatically_derived] - impl<'de> _serde::Deserialize<'de> for Void { - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - #[allow(non_camel_case_types)] - enum __Field {} - struct __FieldVisitor; - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "variant identifier") - } - fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"variant index 0 <= i < 0", - )), - } - } - fn visit_str<__E>(self, __value: &str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - _ => _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )), - } - } - fn visit_bytes<__E>( - self, - __value: &[u8], - ) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - _ => { - let __value = &_serde::export::from_utf8_lossy(__value); - _serde::export::Err(_serde::de::Error::unknown_variant( - __value, VARIANTS, - )) - } - } - } - } - impl<'de> _serde::Deserialize<'de> for __Field { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - struct __Visitor<'de> { - marker: _serde::export::PhantomData, - lifetime: _serde::export::PhantomData<&'de ()>, - } - impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> { - type Value = Void; - fn expecting( - &self, - __formatter: &mut _serde::export::Formatter, - ) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(__formatter, "enum Void") - } - fn visit_enum<__A>( - self, - __data: __A, - ) -> _serde::export::Result - where - __A: _serde::de::EnumAccess<'de>, - { - _serde::export::Result::map( - _serde::de::EnumAccess::variant::<__Field>(__data), - |(__impossible, _)| match __impossible {}, - ) - } - } - const VARIANTS: &'static [&'static str] = &[]; - _serde::Deserializer::deserialize_enum( - __deserializer, - "Void", - VARIANTS, - __Visitor { - marker: _serde::export::PhantomData::, - lifetime: _serde::export::PhantomData, - }, - ) - } - } -}; diff --git a/test_suite/tests/expand/void.rs b/test_suite/tests/expand/void.rs deleted file mode 100644 index bd0d7f4a8..000000000 --- a/test_suite/tests/expand/void.rs +++ /dev/null @@ -1,4 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -enum Void {} diff --git a/test_suite/tests/expandtest.rs b/test_suite/tests/expandtest.rs deleted file mode 100644 index 84516970f..000000000 --- a/test_suite/tests/expandtest.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[cfg_attr(target_os = "emscripten", ignore)] -#[cfg_attr(not(expandtest), ignore)] -#[rustversion::attr(not(nightly), ignore)] -#[allow(unused_attributes)] -#[test] -fn expandtest() { - macrotest::expand("tests/expand/*.rs"); -} diff --git a/test_suite/tests/macros/mod.rs b/test_suite/tests/macros/mod.rs index 2c5a8fa28..44b98ae2f 100644 --- a/test_suite/tests/macros/mod.rs +++ b/test_suite/tests/macros/mod.rs @@ -1,93 +1,77 @@ +#![allow(unused_macro_rules)] + +use serde_test::Token; +use std::iter; + macro_rules! btreeset { () => { BTreeSet::new() }; - ($($value:expr),+) => { - { - let mut set = BTreeSet::new(); - $(set.insert($value);)+ - set - } - } + ($($value:expr),+) => {{ + let mut set = BTreeSet::new(); + $(set.insert($value);)+ + set + }}; } macro_rules! btreemap { () => { BTreeMap::new() }; - ($($key:expr => $value:expr),+) => { - { - let mut map = BTreeMap::new(); - $(map.insert($key, $value);)+ - map - } - } + ($($key:expr => $value:expr),+) => {{ + let mut map = BTreeMap::new(); + $(map.insert($key, $value);)+ + map + }}; } macro_rules! hashset { () => { HashSet::new() }; - ($($value:expr),+) => { - { - let mut set = HashSet::new(); - $(set.insert($value);)+ - set - } - }; - ($hasher:ident @ $($value:expr),+) => { - { - use std::hash::BuildHasherDefault; - let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default()); - $(set.insert($value);)+ - set - } - } + ($($value:expr),+) => {{ + let mut set = HashSet::new(); + $(set.insert($value);)+ + set + }}; + ($hasher:ty; $($value:expr),+) => {{ + let mut set = HashSet::<_, $hasher>::default(); + $(set.insert($value);)+ + set + }}; } macro_rules! hashmap { () => { HashMap::new() }; - ($($key:expr => $value:expr),+) => { - { - let mut map = HashMap::new(); - $(map.insert($key, $value);)+ - map - } - }; - ($hasher:ident @ $($key:expr => $value:expr),+) => { - { - use std::hash::BuildHasherDefault; - let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default()); - $(map.insert($key, $value);)+ - map - } - } + ($($key:expr => $value:expr),+) => {{ + let mut map = HashMap::new(); + $(map.insert($key, $value);)+ + map + }}; + ($hasher:ty; $($key:expr => $value:expr),+) => {{ + let mut map = HashMap::<_, _, $hasher>::default(); + $(map.insert($key, $value);)+ + map + }}; } -macro_rules! seq_impl { - (seq $first:expr,) => { - seq_impl!(seq $first) - }; - ($first:expr,) => { - seq_impl!($first) - }; - (seq $first:expr) => { - $first.into_iter() - }; - ($first:expr) => { - Some($first).into_iter() - }; - (seq $first:expr , $( $elem: tt)*) => { - $first.into_iter().chain(seq!( $($elem)* )) - }; - ($first:expr , $($elem: tt)*) => { - Some($first).into_iter().chain(seq!( $($elem)* )) +pub trait SingleTokenIntoIterator { + fn into_iter(self) -> iter::Once; +} + +impl SingleTokenIntoIterator for Token { + fn into_iter(self) -> iter::Once { + iter::once(self) } } + macro_rules! seq { - ($($tt: tt)*) => { - seq_impl!($($tt)*).collect::>() - }; + ($($elem:expr),* $(,)?) => {{ + use crate::macros::SingleTokenIntoIterator; + let mut vec = Vec::new(); + $( as Extend>::extend(&mut vec, $elem.into_iter());)* + vec + }}; } diff --git a/test_suite/tests/regression.rs b/test_suite/tests/regression.rs new file mode 100644 index 000000000..fb2b25c89 --- /dev/null +++ b/test_suite/tests/regression.rs @@ -0,0 +1,3 @@ +mod regression { + automod::dir!("tests/regression"); +} diff --git a/test_suite/tests/regression/issue1904.rs b/test_suite/tests/regression/issue1904.rs new file mode 100644 index 000000000..b1d5c7314 --- /dev/null +++ b/test_suite/tests/regression/issue1904.rs @@ -0,0 +1,66 @@ +#![allow(dead_code)] // we do not read enum fields + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +pub struct Nested; + +#[derive(Deserialize)] +pub enum ExternallyTagged1 { + Tuple(f64, String), + Flatten { + #[serde(flatten)] + nested: Nested, + }, +} + +#[derive(Deserialize)] +pub enum ExternallyTagged2 { + Flatten { + #[serde(flatten)] + nested: Nested, + }, + Tuple(f64, String), +} + +// Internally tagged enums cannot contain tuple variants so not tested here + +#[derive(Deserialize)] +#[serde(tag = "tag", content = "content")] +pub enum AdjacentlyTagged1 { + Tuple(f64, String), + Flatten { + #[serde(flatten)] + nested: Nested, + }, +} + +#[derive(Deserialize)] +#[serde(tag = "tag", content = "content")] +pub enum AdjacentlyTagged2 { + Flatten { + #[serde(flatten)] + nested: Nested, + }, + Tuple(f64, String), +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum Untagged1 { + Tuple(f64, String), + Flatten { + #[serde(flatten)] + nested: Nested, + }, +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum Untagged2 { + Flatten { + #[serde(flatten)] + nested: Nested, + }, + Tuple(f64, String), +} diff --git a/test_suite/tests/regression/issue2371.rs b/test_suite/tests/regression/issue2371.rs new file mode 100644 index 000000000..668ee5c70 --- /dev/null +++ b/test_suite/tests/regression/issue2371.rs @@ -0,0 +1,53 @@ +#![allow(dead_code)] + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +pub struct Nested; + +#[derive(Deserialize)] +pub enum ExternallyTagged { + Flatten { + #[serde(flatten)] + #[allow(dead_code)] + nested: Nested, + #[allow(dead_code)] + string: &'static str, + }, +} + +#[derive(Deserialize)] +#[serde(tag = "tag")] +pub enum InternallyTagged { + Flatten { + #[serde(flatten)] + #[allow(dead_code)] + nested: Nested, + #[allow(dead_code)] + string: &'static str, + }, +} + +#[derive(Deserialize)] +#[serde(tag = "tag", content = "content")] +pub enum AdjacentlyTagged { + Flatten { + #[serde(flatten)] + #[allow(dead_code)] + nested: Nested, + #[allow(dead_code)] + string: &'static str, + }, +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum UntaggedWorkaround { + Flatten { + #[serde(flatten)] + #[allow(dead_code)] + nested: Nested, + #[allow(dead_code)] + string: &'static str, + }, +} diff --git a/test_suite/tests/regression/issue2409.rs b/test_suite/tests/regression/issue2409.rs new file mode 100644 index 000000000..335344a29 --- /dev/null +++ b/test_suite/tests/regression/issue2409.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +use serde_derive::Deserialize; + +macro_rules! bug { + ($serde_path:literal) => { + #[derive(Deserialize)] + #[serde(crate = $serde_path)] + pub struct Struct; + }; +} + +bug!("serde"); diff --git a/test_suite/tests/regression/issue2415.rs b/test_suite/tests/regression/issue2415.rs new file mode 100644 index 000000000..58a6b60b0 --- /dev/null +++ b/test_suite/tests/regression/issue2415.rs @@ -0,0 +1,6 @@ +use serde_derive::Serialize; + +#[derive(Serialize)] +#[serde()] +#[allow(dead_code)] +pub struct S; diff --git a/test_suite/tests/regression/issue2565.rs b/test_suite/tests/regression/issue2565.rs new file mode 100644 index 000000000..f13cacf04 --- /dev/null +++ b/test_suite/tests/regression/issue2565.rs @@ -0,0 +1,48 @@ +use serde_derive::{Deserialize, Serialize}; +use serde_test::{assert_tokens, Token}; + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +enum Enum { + Simple { + a: i32, + }, + Flatten { + #[serde(flatten)] + flatten: (), + a: i32, + }, +} + +#[test] +fn simple_variant() { + assert_tokens( + &Enum::Simple { a: 42 }, + &[ + Token::StructVariant { + name: "Enum", + variant: "Simple", + len: 1, + }, + Token::Str("a"), + Token::I32(42), + Token::StructVariantEnd, + ], + ); +} + +#[test] +fn flatten_variant() { + assert_tokens( + &Enum::Flatten { flatten: (), a: 42 }, + &[ + Token::NewtypeVariant { + name: "Enum", + variant: "Flatten", + }, + Token::Map { len: None }, + Token::Str("a"), + Token::I32(42), + Token::MapEnd, + ], + ); +} diff --git a/test_suite/tests/regression/issue2792.rs b/test_suite/tests/regression/issue2792.rs new file mode 100644 index 000000000..a8c1604ca --- /dev/null +++ b/test_suite/tests/regression/issue2792.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] // we do not read enum fields + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +pub enum A { + B { + c: String, + }, + D { + #[serde(flatten)] + e: E, + }, +} + +#[derive(Deserialize)] +pub struct E {} diff --git a/test_suite/tests/regression/issue2844.rs b/test_suite/tests/regression/issue2844.rs new file mode 100644 index 000000000..024e62fb0 --- /dev/null +++ b/test_suite/tests/regression/issue2844.rs @@ -0,0 +1,33 @@ +#![allow(clippy::trivially_copy_pass_by_ref, dead_code)] + +use serde_derive::{Deserialize, Serialize}; + +macro_rules! declare_in_macro { + ($with:literal) => { + #[derive(Serialize, Deserialize)] + pub struct S { + #[serde(with = $with)] + f: i32, + } + }; +} + +declare_in_macro!("with"); + +mod with { + use serde::{Deserializer, Serializer}; + + pub fn serialize(_: &i32, _: S) -> Result + where + S: Serializer, + { + unimplemented!() + } + + pub fn deserialize<'de, D>(_: D) -> Result + where + D: Deserializer<'de>, + { + unimplemented!() + } +} diff --git a/test_suite/tests/regression/issue2846.rs b/test_suite/tests/regression/issue2846.rs new file mode 100644 index 000000000..4a6d39531 --- /dev/null +++ b/test_suite/tests/regression/issue2846.rs @@ -0,0 +1,27 @@ +#![allow(clippy::trivially_copy_pass_by_ref, dead_code)] + +use serde_derive::Deserialize; + +macro_rules! declare_in_macro { + ($with:literal) => { + #[derive(Deserialize)] + pub struct S( + #[serde(with = $with)] + #[allow(dead_code)] + i32, + ); + }; +} + +declare_in_macro!("with"); + +mod with { + use serde::Deserializer; + + pub fn deserialize<'de, D>(_: D) -> Result + where + D: Deserializer<'de>, + { + unimplemented!() + } +} diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index 7604fe031..3f02a61fc 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -1,17 +1,26 @@ -#![allow(clippy::cast_lossless, clippy::trivially_copy_pass_by_ref)] - -use serde::de::{self, MapAccess, Unexpected, Visitor}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use std::collections::{BTreeMap, HashMap}; -use std::convert::TryFrom; -use std::fmt; -use std::marker::PhantomData; - +#![allow( + clippy::cast_lossless, + clippy::derive_partial_eq_without_eq, + clippy::from_over_into, + // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 + clippy::nonstandard_macro_braces, + clippy::too_many_lines, + clippy::trivially_copy_pass_by_ref, + clippy::type_repetition_in_bounds, + clippy::uninlined_format_args, +)] + +use serde::de::{self, Deserialize, Deserializer, IgnoredAny, MapAccess, Unexpected, Visitor}; +use serde::ser::{Serialize, Serializer}; +use serde_derive::{Deserialize, Serialize}; use serde_test::{ assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error, assert_tokens, Token, }; +use std::collections::{BTreeMap, HashMap}; +use std::convert::TryFrom; +use std::fmt; +use std::marker::PhantomData; trait MyDefault: Sized { fn my_default() -> Self; @@ -105,42 +114,6 @@ struct CollectOther { extra: HashMap, } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructEnumWrapper { - #[serde(flatten)] - data: FlattenStructEnum, - #[serde(flatten)] - extra: HashMap, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -enum FlattenStructEnum { - InsertInteger { index: u32, value: u32 }, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumWrapper { - outer: u32, - #[serde(flatten)] - data: FlattenStructTagContentEnumNewtype, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumNewtype(pub FlattenStructTagContentEnum); - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "type", content = "value")] -enum FlattenStructTagContentEnum { - InsertInteger { index: u32, value: u32 }, - NewtypeVariant(FlattenStructTagContentEnumNewtypeVariant), -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumNewtypeVariant { - value: u32, -} - #[test] fn test_default_struct() { assert_de_tokens( @@ -632,7 +605,7 @@ fn test_unknown_field_rename_struct() { Token::Str("a4"), Token::I32(3), ], - "unknown field `a4`, expected one of `a1`, `a2`, `a6`", + "unknown field `a4`, expected one of `a1`, `a2`, `a3`, `a5`, `a6`", ); } @@ -770,7 +743,7 @@ fn test_rename_enum() { Token::StructVariant { name: "AliasEnum", variant: "sailor_moon", - len: 3, + len: 5, }, Token::Str("a"), Token::I8(0), @@ -788,7 +761,7 @@ fn test_rename_enum() { Token::StructVariant { name: "AliasEnum", variant: "usagi_tsukino", - len: 3, + len: 5, }, Token::Str("a"), Token::I8(0), @@ -809,7 +782,7 @@ fn test_unknown_field_rename_enum() { variant: "SailorMoon", len: 3, }], - "unknown variant `SailorMoon`, expected `sailor_moon`", + "unknown variant `SailorMoon`, expected `sailor_moon` or `usagi_tsukino`", ); assert_de_tokens_error::( @@ -817,7 +790,7 @@ fn test_unknown_field_rename_enum() { Token::StructVariant { name: "AliasEnum", variant: "usagi_tsukino", - len: 3, + len: 5, }, Token::Str("a"), Token::I8(0), @@ -826,7 +799,7 @@ fn test_unknown_field_rename_enum() { Token::Str("d"), Token::I8(2), ], - "unknown field `d`, expected one of `a`, `b`, `f`", + "unknown field `d`, expected one of `a`, `b`, `c`, `e`, `f`", ); } @@ -1226,7 +1199,7 @@ fn serialize_variant_as_string(f1: &str, f2: &u8, serializer: S) -> Result(deserializer: D) -> Result<(String, u8), D::Error> @@ -1235,22 +1208,17 @@ where { let s = String::deserialize(deserializer)?; let mut pieces = s.split(';'); - let f1 = match pieces.next() { - Some(x) => x, - None => return Err(de::Error::invalid_length(0, &"2")), + let Some(f1) = pieces.next() else { + return Err(de::Error::invalid_length(0, &"2")); }; - let f2 = match pieces.next() { - Some(x) => x, - None => return Err(de::Error::invalid_length(1, &"2")), + let Some(f2) = pieces.next() else { + return Err(de::Error::invalid_length(1, &"2")); }; - let f2 = match f2.parse() { - Ok(n) => n, - Err(_) => { - return Err(de::Error::invalid_value( - Unexpected::Str(f2), - &"an 8-bit signed integer", - )); - } + let Ok(f2) = f2.parse() else { + return Err(de::Error::invalid_value( + Unexpected::Str(f2), + &"an 8-bit signed integer", + )); }; Ok((f1.into(), f2)) } @@ -1528,7 +1496,7 @@ fn test_invalid_length_enum() { Token::TupleVariant { name: "InvalidLengthEnum", variant: "B", - len: 3, + len: 2, }, Token::I32(1), Token::TupleVariantEnd, @@ -1640,996 +1608,1969 @@ fn test_collect_other() { } #[test] -fn test_flatten_struct_enum() { - let mut extra = HashMap::new(); - extra.insert("extra_key".into(), "extra value".into()); - let change_request = FlattenStructEnumWrapper { - data: FlattenStructEnum::InsertInteger { - index: 0, - value: 42, - }, - extra, - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("insert_integer"), - Token::Map { len: None }, - Token::Str("index"), - Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::MapEnd, - Token::Str("extra_key"), - Token::Str("extra value"), - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, +fn test_partially_untagged_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Exp { + Lambda(u32, Box), + #[serde(untagged)] + App(Box, Box), + #[serde(untagged)] + Var(u32), + } + use Exp::*; + + let data = Lambda(0, Box::new(App(Box::new(Var(0)), Box::new(Var(0))))); + assert_tokens( + &data, &[ - Token::Map { len: None }, - Token::Str("insert_integer"), - Token::Struct { + Token::TupleVariant { + name: "Exp", + variant: "Lambda", len: 2, - name: "insert_integer", }, - Token::Str("index"), Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::StructEnd, - Token::Str("extra_key"), - Token::Str("extra value"), - Token::MapEnd, - ], - ); -} - -#[test] -fn test_flatten_struct_tag_content_enum() { - let change_request = FlattenStructTagContentEnumWrapper { - outer: 42, - data: FlattenStructTagContentEnumNewtype(FlattenStructTagContentEnum::InsertInteger { - index: 0, - value: 42, - }), - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("insert_integer"), - Token::Str("value"), - Token::Map { len: None }, - Token::Str("index"), + Token::Tuple { len: 2 }, Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::MapEnd, - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("insert_integer"), - Token::Str("value"), - Token::Struct { - len: 2, - name: "insert_integer", - }, - Token::Str("index"), Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::StructEnd, - Token::MapEnd, + Token::TupleEnd, + Token::TupleVariantEnd, ], ); } #[test] -fn test_flatten_struct_tag_content_enum_newtype() { - let change_request = FlattenStructTagContentEnumWrapper { - outer: 42, - data: FlattenStructTagContentEnumNewtype(FlattenStructTagContentEnum::NewtypeVariant( - FlattenStructTagContentEnumNewtypeVariant { value: 23 }, - )), - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("newtype_variant"), - Token::Str("value"), - Token::Map { len: None }, - Token::Str("value"), - Token::U32(23), - Token::MapEnd, - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("newtype_variant"), - Token::Str("value"), - Token::Struct { - len: 1, - name: "FlattenStructTagContentEnumNewtypeVariant", - }, - Token::Str("value"), - Token::U32(23), - Token::StructEnd, - Token::MapEnd, - ], - ); -} +fn test_partially_untagged_enum_generic() { + trait Trait { + type Assoc; + type Assoc2; + } -#[test] -fn test_unknown_field_in_flatten() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(deny_unknown_fields)] - struct Outer { - dummy: String, - #[serde(flatten)] - inner: Inner, + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum E + where + A: Trait, + { + A(A::Assoc), + #[serde(untagged)] + B(A::Assoc2), } - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Inner { - foo: HashMap, + impl Trait for () { + type Assoc = T; + type Assoc2 = bool; } - assert_de_tokens_error::( + type MyE = E<(), bool, u32>; + use E::*; + + assert_tokens::(&B(true), &[Token::Bool(true)]); + + assert_tokens::( + &A(5), &[ - Token::Struct { - name: "Outer", - len: 1, + Token::NewtypeVariant { + name: "E", + variant: "A", }, - Token::Str("dummy"), - Token::Str("23"), - Token::Str("foo"), - Token::Map { len: None }, - Token::Str("a"), - Token::U32(1), - Token::Str("b"), - Token::U32(2), - Token::MapEnd, - Token::Str("bar"), - Token::U32(23), - Token::StructEnd, + Token::U32(5), ], - "unknown field `bar`", ); } #[test] -fn test_complex_flatten() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Outer { - y: u32, - #[serde(flatten)] - first: First, - #[serde(flatten)] - second: Second, - z: u32, +fn test_partially_untagged_enum_desugared() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Test { + A(u32, u32), + B(u32), + #[serde(untagged)] + C(u32), + #[serde(untagged)] + D(u32, u32), + } + use Test::*; + + mod desugared { + use super::*; + #[derive(Serialize, Deserialize, PartialEq, Debug)] + pub(super) enum Test { + A(u32, u32), + B(u32), + } + } + use desugared::Test as TestTagged; + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(untagged)] + enum TestUntagged { + Tagged(TestTagged), + C(u32), + D(u32, u32), } - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct First { - a: u32, - b: bool, - c: Vec, - d: String, - e: Option, + impl From for TestUntagged { + fn from(test: Test) -> Self { + match test { + A(x, y) => TestUntagged::Tagged(TestTagged::A(x, y)), + B(x) => TestUntagged::Tagged(TestTagged::B(x)), + C(x) => TestUntagged::C(x), + D(x, y) => TestUntagged::D(x, y), + } + } } - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Second { - f: u32, + fn assert_tokens_desugared(value: Test, tokens: &[Token]) { + assert_tokens(&value, tokens); + let desugared: TestUntagged = value.into(); + assert_tokens(&desugared, tokens); } - assert_de_tokens( - &Outer { - y: 0, - first: First { - a: 1, - b: true, - c: vec!["a".into(), "b".into()], - d: "c".into(), - e: Some(2), - }, - second: Second { f: 3 }, - z: 4, - }, + assert_tokens_desugared( + A(0, 1), &[ - Token::Map { len: None }, - Token::Str("y"), + Token::TupleVariant { + name: "Test", + variant: "A", + len: 2, + }, Token::U32(0), - Token::Str("a"), Token::U32(1), - Token::Str("b"), - Token::Bool(true), - Token::Str("c"), - Token::Seq { len: Some(2) }, - Token::Str("a"), - Token::Str("b"), - Token::SeqEnd, - Token::Str("d"), - Token::Str("c"), - Token::Str("e"), - Token::U64(2), - Token::Str("f"), - Token::U32(3), - Token::Str("z"), - Token::U32(4), - Token::MapEnd, + Token::TupleVariantEnd, ], ); - assert_ser_tokens( - &Outer { - y: 0, - first: First { - a: 1, - b: true, - c: vec!["a".into(), "b".into()], - d: "c".into(), - e: Some(2), - }, - second: Second { f: 3 }, - z: 4, - }, + assert_tokens_desugared( + B(1), &[ - Token::Map { len: None }, - Token::Str("y"), - Token::U32(0), - Token::Str("a"), + Token::NewtypeVariant { + name: "Test", + variant: "B", + }, Token::U32(1), - Token::Str("b"), - Token::Bool(true), - Token::Str("c"), - Token::Seq { len: Some(2) }, - Token::Str("a"), - Token::Str("b"), - Token::SeqEnd, - Token::Str("d"), - Token::Str("c"), - Token::Str("e"), - Token::Some, - Token::U64(2), - Token::Str("f"), + ], + ); + + assert_tokens_desugared(C(2), &[Token::U32(2)]); + + assert_tokens_desugared( + D(3, 5), + &[ + Token::Tuple { len: 2 }, Token::U32(3), - Token::Str("z"), - Token::U32(4), - Token::MapEnd, + Token::U32(5), + Token::TupleEnd, ], ); } #[test] -fn test_flatten_map_twice() { - #[derive(Debug, PartialEq, Deserialize)] - struct Outer { - #[serde(flatten)] - first: BTreeMap, - #[serde(flatten)] - between: Inner, - #[serde(flatten)] - second: BTreeMap, +fn test_partially_untagged_internally_tagged_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(tag = "t")] + enum Data { + A, + B, + #[serde(untagged)] + Var(u32), } - #[derive(Debug, PartialEq, Deserialize)] - struct Inner { - y: String, - } + let data = Data::A; assert_de_tokens( - &Outer { - first: { - let mut first = BTreeMap::new(); - first.insert("x".to_owned(), "X".to_owned()); - first.insert("y".to_owned(), "Y".to_owned()); - first - }, - between: Inner { y: "Y".to_owned() }, - second: { - let mut second = BTreeMap::new(); - second.insert("x".to_owned(), "X".to_owned()); - second - }, - }, + &data, &[ Token::Map { len: None }, - Token::Str("x"), - Token::Str("X"), - Token::Str("y"), - Token::Str("Y"), + Token::Str("t"), + Token::Str("A"), Token::MapEnd, ], ); + + let data = Data::Var(42); + + assert_de_tokens(&data, &[Token::U32(42)]); + + // TODO test error output } #[test] -fn test_flatten_unit() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Response { - #[serde(flatten)] - data: T, - status: usize, +fn test_transparent_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(transparent)] + struct Transparent { + #[serde(skip)] + a: bool, + b: u32, + #[serde(skip)] + c: bool, + d: PhantomData<()>, } assert_tokens( - &Response { - data: (), - status: 0, + &Transparent { + a: false, + b: 1, + c: false, + d: PhantomData, }, - &[ - Token::Map { len: None }, - Token::Str("status"), - Token::U64(0), - Token::MapEnd, - ], + &[Token::U32(1)], + ); +} + +#[test] +fn test_transparent_tuple_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(transparent)] + struct Transparent( + #[serde(skip)] bool, + u32, + #[serde(skip)] bool, + PhantomData<()>, ); + + assert_tokens(&Transparent(false, 1, false, PhantomData), &[Token::U32(1)]); } #[test] -fn test_flatten_unsupported_type() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Outer { - outer: String, - #[serde(flatten)] - inner: String, +fn test_expecting_message() { + #[derive(Deserialize, PartialEq, Debug)] + #[serde(expecting = "something strange...")] + struct Unit; + + #[derive(Deserialize)] + #[serde(expecting = "something strange...")] + struct Newtype(bool); + + #[derive(Deserialize)] + #[serde(expecting = "something strange...")] + struct Tuple(u32, bool); + + #[derive(Deserialize)] + #[serde(expecting = "something strange...")] + struct Struct { + #[allow(dead_code)] + question: String, + #[allow(dead_code)] + answer: u32, } - assert_ser_tokens_error( - &Outer { - outer: "foo".into(), - inner: "bar".into(), - }, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::Str("foo"), - ], - "can only flatten structs and maps (got a string)", + assert_de_tokens_error::( + &[Token::Str("Unit")], + r#"invalid type: string "Unit", expected something strange..."#, ); - assert_de_tokens_error::( - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::Str("foo"), - Token::Str("a"), - Token::Str("b"), - Token::MapEnd, - ], - "can only flatten structs and maps", + + assert_de_tokens_error::( + &[Token::Str("Newtype")], + r#"invalid type: string "Newtype", expected something strange..."#, + ); + + assert_de_tokens_error::( + &[Token::Str("Tuple")], + r#"invalid type: string "Tuple", expected something strange..."#, + ); + + assert_de_tokens_error::( + &[Token::Str("Struct")], + r#"invalid type: string "Struct", expected something strange..."#, ); } #[test] -fn test_non_string_keys() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct TestStruct { - name: String, - age: u32, - #[serde(flatten)] - mapping: HashMap, +fn test_expecting_message_externally_tagged_enum() { + #[derive(Deserialize)] + #[serde(expecting = "something strange...")] + enum Enum { + ExternallyTagged, } - let mut mapping = HashMap::new(); - mapping.insert(0, 42); - assert_tokens( - &TestStruct { - name: "peter".into(), - age: 3, - mapping, - }, - &[ - Token::Map { len: None }, - Token::Str("name"), - Token::Str("peter"), - Token::Str("age"), - Token::U32(3), - Token::U32(0), - Token::U32(42), - Token::MapEnd, - ], + assert_de_tokens_error::( + &[Token::Str("ExternallyTagged")], + r#"invalid type: string "ExternallyTagged", expected something strange..."#, + ); + + // Check that #[serde(expecting = "...")] doesn't affect variant identifier error message + assert_de_tokens_error::( + &[Token::Enum { name: "Enum" }, Token::Unit], + "invalid type: unit value, expected variant identifier", ); } #[test] -fn test_lifetime_propagation_for_flatten() { - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde(flatten)] - t: T, +fn test_expecting_message_identifier_enum() { + #[derive(Deserialize)] + #[serde(field_identifier)] + #[serde(expecting = "something strange...")] + enum FieldEnum { + Field, } - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct B<'a> { - #[serde(flatten, borrow)] - t: HashMap<&'a str, u32>, + #[derive(Deserialize)] + #[serde(variant_identifier)] + #[serde(expecting = "something strange...")] + enum VariantEnum { + Variant, } - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct C<'a> { - #[serde(flatten, borrow)] - t: HashMap<&'a [u8], u32>, - } + assert_de_tokens_error::( + &[Token::Unit], + "invalid type: unit value, expected something strange...", + ); - let mut owned_map = HashMap::new(); - owned_map.insert("x".to_string(), 42u32); - assert_tokens( - &A { t: owned_map }, + assert_de_tokens_error::( &[ - Token::Map { len: None }, - Token::Str("x"), - Token::U32(42), - Token::MapEnd, + Token::Enum { name: "FieldEnum" }, + Token::Str("Unknown"), + Token::None, ], + "invalid type: map, expected something strange...", ); - let mut borrowed_map = HashMap::new(); - borrowed_map.insert("x", 42u32); - assert_ser_tokens( - &B { - t: borrowed_map.clone(), - }, - &[ - Token::Map { len: None }, - Token::BorrowedStr("x"), - Token::U32(42), - Token::MapEnd, - ], + assert_de_tokens_error::( + &[Token::Unit], + "invalid type: unit value, expected something strange...", ); - assert_de_tokens( - &B { t: borrowed_map }, + assert_de_tokens_error::( &[ - Token::Map { len: None }, - Token::BorrowedStr("x"), - Token::U32(42), - Token::MapEnd, + Token::Enum { + name: "VariantEnum", + }, + Token::Str("Unknown"), + Token::None, ], + "invalid type: map, expected something strange...", ); +} - let mut borrowed_map = HashMap::new(); - borrowed_map.insert(&b"x"[..], 42u32); - assert_ser_tokens( - &C { - t: borrowed_map.clone(), - }, - &[ - Token::Map { len: None }, - Token::Seq { len: Some(1) }, - Token::U8(120), - Token::SeqEnd, - Token::U32(42), - Token::MapEnd, - ], - ); +mod flatten { + use super::*; - assert_de_tokens( - &C { t: borrowed_map }, - &[ - Token::Map { len: None }, - Token::BorrowedBytes(b"x"), - Token::U32(42), - Token::MapEnd, - ], - ); -} + #[test] + fn complex() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Outer { + y: u32, + #[serde(flatten)] + first: First, + #[serde(flatten)] + second: Second, + z: u32, + } -#[test] -fn test_flatten_enum_newtype() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct S { - #[serde(flatten)] - flat: E, - } + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct First { + a: u32, + b: bool, + c: Vec, + d: String, + e: Option, + } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - enum E { - Q(HashMap), + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Second { + f: u32, + } + + assert_de_tokens( + &Outer { + y: 0, + first: First { + a: 1, + b: true, + c: vec!["a".into(), "b".into()], + d: "c".into(), + e: Some(2), + }, + second: Second { f: 3 }, + z: 4, + }, + &[ + Token::Map { len: None }, + Token::Str("y"), + Token::U32(0), + Token::Str("a"), + Token::U32(1), + Token::Str("b"), + Token::Bool(true), + Token::Str("c"), + Token::Seq { len: Some(2) }, + Token::Str("a"), + Token::Str("b"), + Token::SeqEnd, + Token::Str("d"), + Token::Str("c"), + Token::Str("e"), + Token::U64(2), + Token::Str("f"), + Token::U32(3), + Token::Str("z"), + Token::U32(4), + Token::MapEnd, + ], + ); + + assert_ser_tokens( + &Outer { + y: 0, + first: First { + a: 1, + b: true, + c: vec!["a".into(), "b".into()], + d: "c".into(), + e: Some(2), + }, + second: Second { f: 3 }, + z: 4, + }, + &[ + Token::Map { len: None }, + Token::Str("y"), + Token::U32(0), + Token::Str("a"), + Token::U32(1), + Token::Str("b"), + Token::Bool(true), + Token::Str("c"), + Token::Seq { len: Some(2) }, + Token::Str("a"), + Token::Str("b"), + Token::SeqEnd, + Token::Str("d"), + Token::Str("c"), + Token::Str("e"), + Token::Some, + Token::U64(2), + Token::Str("f"), + Token::U32(3), + Token::Str("z"), + Token::U32(4), + Token::MapEnd, + ], + ); } - let e = E::Q({ - let mut map = HashMap::new(); - map.insert("k".to_owned(), "v".to_owned()); - map - }); - let s = S { flat: e }; + #[test] + fn map_twice() { + #[derive(Debug, PartialEq, Deserialize)] + struct Outer { + #[serde(flatten)] + first: BTreeMap, + #[serde(flatten)] + between: Inner, + #[serde(flatten)] + second: BTreeMap, + } - assert_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("Q"), - Token::Map { len: Some(1) }, - Token::Str("k"), - Token::Str("v"), - Token::MapEnd, - Token::MapEnd, - ], - ); -} + #[derive(Debug, PartialEq, Deserialize)] + struct Inner { + y: String, + } -#[test] -fn test_flatten_internally_tagged() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct S { - #[serde(flatten)] - x: X, - #[serde(flatten)] - y: Y, + assert_de_tokens( + &Outer { + first: { + let mut first = BTreeMap::new(); + first.insert("x".to_owned(), "X".to_owned()); + first.insert("y".to_owned(), "Y".to_owned()); + first + }, + between: Inner { y: "Y".to_owned() }, + second: { + let mut second = BTreeMap::new(); + second.insert("x".to_owned(), "X".to_owned()); + second + }, + }, + &[ + Token::Map { len: None }, + Token::Str("x"), + Token::Str("X"), + Token::Str("y"), + Token::Str("Y"), + Token::MapEnd, + ], + ); } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(tag = "typeX")] - enum X { - A { a: i32 }, - B { b: i32 }, - } + #[test] + fn unsupported_type() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Outer { + outer: String, + #[serde(flatten)] + inner: String, + } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(tag = "typeY")] - enum Y { - C { c: i32 }, - D { d: i32 }, + assert_ser_tokens_error( + &Outer { + outer: "foo".into(), + inner: "bar".into(), + }, + &[ + Token::Map { len: None }, + Token::Str("outer"), + Token::Str("foo"), + ], + "can only flatten structs and maps (got a string)", + ); + assert_de_tokens_error::( + &[ + Token::Map { len: None }, + Token::Str("outer"), + Token::Str("foo"), + Token::Str("a"), + Token::Str("b"), + Token::MapEnd, + ], + "can only flatten structs and maps", + ); } - let s = S { - x: X::B { b: 1 }, - y: Y::D { d: 2 }, - }; + #[test] + fn unknown_field() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(deny_unknown_fields)] + struct Outer { + dummy: String, + #[serde(flatten)] + inner: Inner, + } - assert_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("typeX"), - Token::Str("B"), - Token::Str("b"), - Token::I32(1), - Token::Str("typeY"), - Token::Str("D"), - Token::Str("d"), - Token::I32(2), - Token::MapEnd, - ], - ); -} + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Inner { + foo: HashMap, + } -#[test] -fn test_externally_tagged_enum_containing_flatten() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - enum Data { - A { - a: i32, - #[serde(flatten)] - flat: Flat, - }, + assert_de_tokens_error::( + &[ + Token::Struct { + name: "Outer", + len: 1, + }, + Token::Str("dummy"), + Token::Str("23"), + Token::Str("foo"), + Token::Map { len: None }, + Token::Str("a"), + Token::U32(1), + Token::Str("b"), + Token::U32(2), + Token::MapEnd, + Token::Str("bar"), + Token::U32(23), + Token::StructEnd, + ], + "unknown field `bar`", + ); } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Flat { - b: i32, + #[test] + fn non_string_keys() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct TestStruct { + name: String, + age: u32, + #[serde(flatten)] + mapping: HashMap, + } + + let mut mapping = HashMap::new(); + mapping.insert(0, 42); + assert_tokens( + &TestStruct { + name: "peter".into(), + age: 3, + mapping, + }, + &[ + Token::Map { len: None }, + Token::Str("name"), + Token::Str("peter"), + Token::Str("age"), + Token::U32(3), + Token::U32(0), + Token::U32(42), + Token::MapEnd, + ], + ); } - let data = Data::A { - a: 0, - flat: Flat { b: 0 }, - }; + #[test] + fn lifetime_propagation() { + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde(flatten)] + t: T, + } - assert_tokens( - &data, - &[ - Token::NewtypeVariant { - name: "Data", - variant: "A", + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct B<'a> { + #[serde(flatten, borrow)] + t: HashMap<&'a str, u32>, + } + + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct C<'a> { + #[serde(flatten, borrow)] + t: HashMap<&'a [u8], u32>, + } + + let mut owned_map = HashMap::new(); + owned_map.insert("x".to_string(), 42u32); + assert_tokens( + &A { t: owned_map }, + &[ + Token::Map { len: None }, + Token::Str("x"), + Token::U32(42), + Token::MapEnd, + ], + ); + + let mut borrowed_map = HashMap::new(); + borrowed_map.insert("x", 42u32); + assert_ser_tokens( + &B { + t: borrowed_map.clone(), + }, + &[ + Token::Map { len: None }, + Token::BorrowedStr("x"), + Token::U32(42), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &B { t: borrowed_map }, + &[ + Token::Map { len: None }, + Token::BorrowedStr("x"), + Token::U32(42), + Token::MapEnd, + ], + ); + + let mut borrowed_map = HashMap::new(); + borrowed_map.insert(&b"x"[..], 42u32); + assert_ser_tokens( + &C { + t: borrowed_map.clone(), + }, + &[ + Token::Map { len: None }, + Token::Seq { len: Some(1) }, + Token::U8(120), + Token::SeqEnd, + Token::U32(42), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &C { t: borrowed_map }, + &[ + Token::Map { len: None }, + Token::BorrowedBytes(b"x"), + Token::U32(42), + Token::MapEnd, + ], + ); + } + + // Regression test for https://github.com/serde-rs/serde/issues/1904 + #[test] + fn enum_tuple_and_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Outer { + Tuple(f64, i32), + Flatten { + #[serde(flatten)] + nested: Nested, }, - Token::Map { len: None }, - Token::Str("a"), - Token::I32(0), - Token::Str("b"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + } -#[test] -fn test_internally_tagged_enum_containing_flatten() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(tag = "t")] - enum Data { - A { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Nested { a: i32, - #[serde(flatten)] - flat: Flat, - }, - } + b: i32, + } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Flat { - b: i32, + assert_tokens( + &Outer::Tuple(1.2, 3), + &[ + Token::TupleVariant { + name: "Outer", + variant: "Tuple", + len: 2, + }, + Token::F64(1.2), + Token::I32(3), + Token::TupleVariantEnd, + ], + ); + assert_tokens( + &Outer::Flatten { + nested: Nested { a: 1, b: 2 }, + }, + &[ + Token::NewtypeVariant { + name: "Outer", + variant: "Flatten", + }, + Token::Map { len: None }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::MapEnd, + ], + ); } - let data = Data::A { - a: 0, - flat: Flat { b: 0 }, - }; + #[test] + fn option() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Outer { + #[serde(flatten)] + inner1: Option, + #[serde(flatten)] + inner2: Option, + } - assert_tokens( - &data, - &[ - Token::Map { len: None }, - Token::Str("t"), - Token::Str("A"), - Token::Str("a"), - Token::I32(0), - Token::Str("b"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Inner1 { + inner1: i32, + } -#[test] -fn test_adjacently_tagged_enum_containing_flatten() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(tag = "t", content = "c")] - enum Data { - A { - a: i32, - #[serde(flatten)] - flat: Flat, - }, + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Inner2 { + inner2: i32, + } + + assert_tokens( + &Outer { + inner1: Some(Inner1 { inner1: 1 }), + inner2: Some(Inner2 { inner2: 2 }), + }, + &[ + Token::Map { len: None }, + Token::Str("inner1"), + Token::I32(1), + Token::Str("inner2"), + Token::I32(2), + Token::MapEnd, + ], + ); + + assert_tokens( + &Outer { + inner1: Some(Inner1 { inner1: 1 }), + inner2: None, + }, + &[ + Token::Map { len: None }, + Token::Str("inner1"), + Token::I32(1), + Token::MapEnd, + ], + ); + + assert_tokens( + &Outer { + inner1: None, + inner2: Some(Inner2 { inner2: 2 }), + }, + &[ + Token::Map { len: None }, + Token::Str("inner2"), + Token::I32(2), + Token::MapEnd, + ], + ); + + assert_tokens( + &Outer { + inner1: None, + inner2: None, + }, + &[Token::Map { len: None }, Token::MapEnd], + ); } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Flat { - b: i32, + #[test] + fn ignored_any() { + #[derive(Deserialize, PartialEq, Debug)] + struct Outer { + #[serde(flatten)] + inner: IgnoredAny, + } + + assert_de_tokens( + &Outer { inner: IgnoredAny }, + &[Token::Map { len: None }, Token::MapEnd], + ); + + assert_de_tokens( + &Outer { inner: IgnoredAny }, + &[ + Token::Struct { + name: "DoNotMatter", + len: 0, + }, + Token::StructEnd, + ], + ); } - let data = Data::A { - a: 0, - flat: Flat { b: 0 }, - }; + #[test] + fn flatten_any_after_flatten_struct() { + #[derive(PartialEq, Debug)] + struct Any; + + impl<'de> Deserialize<'de> for Any { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct AnyVisitor; + + impl<'de> Visitor<'de> for AnyVisitor { + type Value = Any; + + fn expecting(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + while let Some((Any, Any)) = map.next_entry()? {} + Ok(Any) + } + } - assert_tokens( - &data, - &[ - Token::Struct { - name: "Data", - len: 2, - }, - Token::Str("t"), - Token::Str("A"), - Token::Str("c"), - Token::Map { len: None }, - Token::Str("a"), - Token::I32(0), - Token::Str("b"), - Token::I32(0), - Token::MapEnd, - Token::StructEnd, - ], - ); -} + deserializer.deserialize_any(AnyVisitor) + } + } -#[test] -fn test_untagged_enum_containing_flatten() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(untagged)] - enum Data { - A { - a: i32, + #[derive(Deserialize, PartialEq, Debug)] + struct Outer { #[serde(flatten)] - flat: Flat, - }, + inner: Inner, + #[serde(flatten)] + extra: Any, + } + + #[derive(Deserialize, PartialEq, Debug)] + struct Inner { + inner: i32, + } + + let s = Outer { + inner: Inner { inner: 0 }, + extra: Any, + }; + + assert_de_tokens( + &s, + &[ + Token::Map { len: None }, + Token::Str("inner"), + Token::I32(0), + Token::MapEnd, + ], + ); } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Flat { - b: i32, + #[test] + fn alias() { + #[derive(Debug, PartialEq, Deserialize)] + struct Outer { + #[serde(flatten)] + a: AliasStruct, + b: i32, + } + + assert_de_tokens( + &Outer { + a: AliasStruct { + a1: 1, + a2: 2, + a4: 4, + }, + b: 7, + }, + &[ + Token::Struct { + name: "Outer", + len: 4, + }, + Token::Str("a1"), + Token::I32(1), + Token::Str("a2"), + Token::I32(2), + Token::Str("a5"), + Token::I32(4), + Token::Str("b"), + Token::I32(7), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Outer { + a: AliasStruct { + a1: 1, + a2: 2, + a4: 4, + }, + b: 7, + }, + &[ + Token::Struct { + name: "Outer", + len: 4, + }, + Token::Str("a1"), + Token::I32(1), + Token::Str("a2"), + Token::I32(2), + Token::Str("a6"), + Token::I32(4), + Token::Str("b"), + Token::I32(7), + Token::StructEnd, + ], + ); } - let data = Data::A { - a: 0, - flat: Flat { b: 0 }, - }; + mod unit { + use super::*; - assert_tokens( - &data, - &[ - Token::Map { len: None }, - Token::Str("a"), - Token::I32(0), - Token::Str("b"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + #[test] + fn unit() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Response { + #[serde(flatten)] + data: T, + status: usize, + } -#[test] -fn test_flatten_untagged_enum() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Outer { - #[serde(flatten)] - inner: Inner, - } + assert_tokens( + &Response { + data: (), + status: 0, + }, + &[ + Token::Map { len: None }, + Token::Str("status"), + Token::U64(0), + Token::MapEnd, + ], + ); + } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(untagged)] - enum Inner { - Variant { a: i32 }, + #[test] + fn unit_struct() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Response { + #[serde(flatten)] + data: T, + status: usize, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Unit; + + assert_tokens( + &Response { + data: Unit, + status: 0, + }, + &[ + Token::Map { len: None }, + Token::Str("status"), + Token::U64(0), + Token::MapEnd, + ], + ); + } } - let data = Outer { - inner: Inner::Variant { a: 0 }, - }; + mod enum_ { + use super::*; + + mod externally_tagged { + use super::*; + use std::iter::FromIterator; + + #[test] + fn straightforward() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Data { + A { + a: i32, + #[serde(flatten)] + flat: Flat, + }, + } - assert_tokens( - &data, - &[ - Token::Map { len: None }, - Token::Str("a"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Flat { + b: i32, + } -#[test] -fn test_flatten_option() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Outer { - #[serde(flatten)] - inner1: Option, - #[serde(flatten)] - inner2: Option, - } + let data = Data::A { + a: 0, + flat: Flat { b: 0 }, + }; + + assert_tokens( + &data, + &[ + Token::NewtypeVariant { + name: "Data", + variant: "A", + }, + Token::Map { len: None }, + Token::Str("a"), + Token::I32(0), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + ], + ); + } - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Inner1 { - inner1: i32, - } + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + data: Enum, - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Inner2 { - inner2: i32, - } + #[serde(flatten)] + extra: HashMap, + } - assert_tokens( - &Outer { - inner1: Some(Inner1 { inner1: 1 }), - inner2: Some(Inner2 { inner2: 2 }), - }, - &[ - Token::Map { len: None }, - Token::Str("inner1"), - Token::I32(1), - Token::Str("inner2"), - Token::I32(2), - Token::MapEnd, - ], - ); + #[derive(Debug, PartialEq, Serialize, Deserialize)] + enum Enum { + Unit, + Newtype(HashMap), + Tuple(u32, u32), + Struct { index: u32, value: u32 }, + } - assert_tokens( - &Outer { - inner1: Some(Inner1 { inner1: 1 }), - inner2: None, - }, - &[ - Token::Map { len: None }, - Token::Str("inner1"), - Token::I32(1), - Token::MapEnd, - ], - ); + #[test] + fn unit() { + let value = Flatten { + data: Enum::Unit, + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // data + Token::Str("Unit"), // variant + Token::Unit, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + // data + Token::Str("Unit"), // variant + Token::Unit, + Token::MapEnd, + ], + ); + } - assert_tokens( - &Outer { - inner1: None, - inner2: Some(Inner2 { inner2: 2 }), - }, - &[ - Token::Map { len: None }, - Token::Str("inner2"), - Token::I32(2), - Token::MapEnd, - ], - ); + #[test] + fn newtype() { + let value = Flatten { + data: Enum::Newtype(HashMap::from_iter([("key".into(), "value".into())])), + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // data + Token::Str("Newtype"), // variant + Token::Map { len: Some(1) }, + Token::Str("key"), + Token::Str("value"), + Token::MapEnd, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + // data + Token::Str("Newtype"), // variant + Token::Map { len: Some(1) }, + Token::Str("key"), + Token::Str("value"), + Token::MapEnd, + Token::MapEnd, + ], + ); + } - assert_tokens( - &Outer { - inner1: None, - inner2: None, - }, - &[Token::Map { len: None }, Token::MapEnd], - ); -} + // Reaches crate::private::de::content::VariantDeserializer::tuple_variant + // Content::Seq case + // via FlatMapDeserializer::deserialize_enum + #[test] + fn tuple() { + let value = Flatten { + data: Enum::Tuple(0, 42), + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // data + Token::Str("Tuple"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), + Token::U32(42), + Token::SeqEnd, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + // data + Token::Str("Tuple"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), + Token::U32(42), + Token::SeqEnd, + Token::MapEnd, + ], + ); + } -#[test] -fn test_transparent_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(transparent)] - struct Transparent { - #[serde(skip)] - a: bool, - b: u32, - #[serde(skip)] - c: bool, - d: PhantomData<()>, - } + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Seq case + // via FlatMapDeserializer::deserialize_enum + #[test] + fn struct_from_seq() { + let value = Flatten { + data: Enum::Struct { + index: 0, + value: 42, + }, + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }; + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // data + Token::Str("Struct"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), // index + Token::U32(42), // value + Token::SeqEnd, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + // data + Token::Str("Struct"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), // index + Token::U32(42), // value + Token::SeqEnd, + Token::MapEnd, + ], + ); + } - assert_tokens( - &Transparent { - a: false, - b: 1, - c: false, - d: PhantomData, - }, - &[Token::U32(1)], - ); -} + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Map case + // via FlatMapDeserializer::deserialize_enum + #[test] + fn struct_from_map() { + let value = Flatten { + data: Enum::Struct { + index: 0, + value: 42, + }, + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // data + Token::Str("Struct"), // variant + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // extra + Token::Str("extra_key"), + Token::Str("extra value"), + // data + Token::Str("Struct"), // variant + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + Token::MapEnd, + ], + ); + } + } -#[test] -fn test_transparent_tuple_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(transparent)] - struct Transparent( - #[serde(skip)] bool, - u32, - #[serde(skip)] bool, - PhantomData<()>, - ); + mod adjacently_tagged { + use super::*; - assert_tokens(&Transparent(false, 1, false, PhantomData), &[Token::U32(1)]); -} + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + outer: u32, -#[test] -fn test_internally_tagged_unit_enum_with_unknown_fields() { - #[derive(Deserialize, PartialEq, Debug)] - #[serde(tag = "t")] - enum Data { - A, - } + #[serde(flatten)] + data: NewtypeWrapper, + } - let data = Data::A; + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeWrapper(pub Enum); - assert_de_tokens( - &data, - &[ - Token::Map { len: None }, - Token::Str("t"), - Token::Str("A"), - Token::Str("b"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag", content = "content")] + enum Enum { + Unit, + Newtype(NewtypeVariant), + Struct { index: u32, value: u32 }, + } -#[test] -fn test_flattened_internally_tagged_unit_enum_with_unknown_fields() { - #[derive(Deserialize, PartialEq, Debug)] - struct S { - #[serde(flatten)] - x: X, - #[serde(flatten)] - y: Y, - } + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeVariant { + value: u32, + } - #[derive(Deserialize, PartialEq, Debug)] - #[serde(tag = "typeX")] - enum X { - A, - } + #[test] + fn unit() { + let value = Flatten { + outer: 42, + data: NewtypeWrapper(Enum::Unit), + }; + // Field order: outer, [tag] + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // content missing + Token::MapEnd, + ], + ); + // Field order: [tag], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // content missing + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: outer, [tag, content] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // content + Token::Str("content"), + Token::Unit, + Token::MapEnd, + ], + ); + // Field order: outer, [content, tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Unit, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + Token::MapEnd, + ], + ); + // Field order: [tag, content], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // content + Token::Str("content"), + Token::Unit, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [content, tag], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Unit, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [tag], outer, [content] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Unit, + Token::MapEnd, + ], + ); + // Field order: [content], outer, [tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Unit, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Unit", + }, + Token::MapEnd, + ], + ); + } - #[derive(Deserialize, PartialEq, Debug)] - #[serde(tag = "typeY")] - enum Y { - B { c: u32 }, - } + #[test] + fn newtype() { + let value = Flatten { + outer: 42, + data: NewtypeWrapper(Enum::Newtype(NewtypeVariant { value: 23 })), + }; + // Field order: outer, [tag, content] + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + Token::MapEnd, + ], + ); + // Field order: outer, [content, tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + Token::MapEnd, + ], + ); + // Field order: [tag, content], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [content, tag], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [tag], outer, [content] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + Token::MapEnd, + ], + ); + // Field order: [content], outer, [tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Newtype", + }, + Token::MapEnd, + ], + ); + } - let s = S { - x: X::A, - y: Y::B { c: 0 }, - }; + #[test] + fn struct_() { + let value = Flatten { + outer: 42, + data: NewtypeWrapper(Enum::Struct { + index: 0, + value: 42, + }), + }; + // Field order: outer, [tag, content] + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + Token::MapEnd, + ], + ); + // Field order: outer, [content, tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + Token::MapEnd, + ], + ); + // Field order: [tag, content], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [content, tag], outer + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + // outer + Token::Str("outer"), + Token::U32(42), + Token::MapEnd, + ], + ); + // Field order: [tag], outer, [content] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + // outer + Token::Str("outer"), + Token::U32(42), + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + Token::MapEnd, + ], + ); + // Field order: [content], outer, [tag] + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // content + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + // outer + Token::Str("outer"), + Token::U32(42), + // tag + Token::Str("tag"), + Token::UnitVariant { + name: "Enum", + variant: "Struct", + }, + Token::MapEnd, + ], + ); + } + } - assert_de_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("typeX"), - Token::Str("A"), - Token::Str("typeY"), - Token::Str("B"), - Token::Str("c"), - Token::I32(0), - Token::MapEnd, - ], - ); -} + mod internally_tagged { + use super::*; + + #[test] + fn structs() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + x: X, + #[serde(flatten)] + y: Y, + } -#[test] -fn test_flatten_any_after_flatten_struct() { - #[derive(PartialEq, Debug)] - struct Any; - - impl<'de> Deserialize<'de> for Any { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct AnyVisitor; - - impl<'de> Visitor<'de> for AnyVisitor { - type Value = Any; - - fn expecting(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { - unimplemented!() + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeX")] + enum X { + A { a: i32 }, + B { b: i32 }, } - fn visit_map(self, mut map: M) -> Result - where - M: MapAccess<'de>, - { - while let Some((Any, Any)) = map.next_entry()? {} - Ok(Any) + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeY")] + enum Y { + C { c: i32 }, + D { d: i32 }, } + + let value = Flatten { + x: X::B { b: 1 }, + y: Y::D { d: 2 }, + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // x + Token::Str("typeX"), + Token::Str("B"), + Token::Str("b"), + Token::I32(1), + // y + Token::Str("typeY"), + Token::Str("D"), + Token::Str("d"), + Token::I32(2), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // y + Token::Str("typeY"), + Token::Str("D"), + Token::Str("d"), + Token::I32(2), + // x + Token::Str("typeX"), + Token::Str("B"), + Token::Str("b"), + Token::I32(1), + Token::MapEnd, + ], + ); } - deserializer.deserialize_any(AnyVisitor) + #[test] + fn unit_enum_with_unknown_fields() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + x: X, + #[serde(flatten)] + y: Y, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeX")] + enum X { + A, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeY")] + enum Y { + B { c: u32 }, + } + + let value = Flatten { + x: X::A, + y: Y::B { c: 0 }, + }; + assert_tokens( + &value, + &[ + Token::Map { len: None }, + // x + Token::Str("typeX"), + Token::Str("A"), + // y + Token::Str("typeY"), + Token::Str("B"), + Token::Str("c"), + Token::U32(0), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + // y + Token::Str("typeY"), + Token::Str("B"), + Token::Str("c"), + Token::U32(0), + // x + Token::Str("typeX"), + Token::Str("A"), + Token::MapEnd, + ], + ); + } } - } - #[derive(Deserialize, PartialEq, Debug)] - struct Outer { - #[serde(flatten)] - inner: Inner, - #[serde(flatten)] - extra: Any, - } + mod untagged { + use super::*; - #[derive(Deserialize, PartialEq, Debug)] - struct Inner { - inner: i32, - } + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + data: Enum, + } - let s = Outer { - inner: Inner { inner: 0 }, - extra: Any, - }; + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Enum { + Struct { a: i32 }, + } - assert_de_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("inner"), - Token::I32(0), - Token::MapEnd, - ], - ); + #[test] + fn struct_() { + assert_tokens( + &Flatten { + data: Enum::Struct { a: 0 }, + }, + &[ + Token::Map { len: None }, + Token::Str("a"), + Token::I32(0), + Token::MapEnd, + ], + ); + } + } + } } diff --git a/test_suite/tests/test_borrow.rs b/test_suite/tests/test_borrow.rs index e76ede69f..6fcdd7c95 100644 --- a/test_suite/tests/test_borrow.rs +++ b/test_suite/tests/test_borrow.rs @@ -1,6 +1,16 @@ -use serde::{Deserialize, Deserializer}; +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::items_after_statements, + clippy::used_underscore_binding, + // We use lots of declarations inside function bodies to avoid conflicts, + // but they aren't used. We just want to make sure they compile. + dead_code, +)] + +use serde::de::value::{BorrowedStrDeserializer, MapDeserializer}; +use serde::de::{Deserialize, Deserializer, IntoDeserializer}; +use serde_derive::Deserialize; use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; - use std::borrow::Cow; #[test] @@ -90,6 +100,30 @@ fn test_struct() { ); } +#[test] +fn test_field_identifier() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(field_identifier)] + enum FieldStr<'a> { + #[serde(borrow)] + Str(&'a str), + } + + assert_de_tokens(&FieldStr::Str("value"), &[Token::BorrowedStr("value")]); + + #[derive(Deserialize, Debug, PartialEq)] + #[serde(field_identifier)] + enum FieldBytes<'a> { + #[serde(borrow)] + Bytes(&'a [u8]), + } + + assert_de_tokens( + &FieldBytes::Bytes(b"value"), + &[Token::BorrowedBytes(b"value")], + ); +} + #[test] fn test_cow() { #[derive(Deserialize)] @@ -100,20 +134,22 @@ fn test_cow() { borrowed: Cow<'b, str>, } - let tokens = &[ - Token::Struct { - name: "Cows", - len: 2, - }, - Token::Str("copied"), - Token::BorrowedStr("copied"), - Token::Str("borrowed"), - Token::BorrowedStr("borrowed"), - Token::StructEnd, - ]; + struct BorrowedStr(&'static str); - let mut de = serde_test::Deserializer::new(tokens); - let cows = Cows::deserialize(&mut de).unwrap(); + impl<'de> IntoDeserializer<'de> for BorrowedStr { + type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>; + + fn into_deserializer(self) -> Self::Deserializer { + BorrowedStrDeserializer::new(self.0) + } + } + + let de = MapDeserializer::new(IntoIterator::into_iter([ + ("copied", BorrowedStr("copied")), + ("borrowed", BorrowedStr("borrowed")), + ])); + + let cows = Cows::deserialize(de).unwrap(); match cows.copied { Cow::Owned(ref s) if s == "copied" => {} @@ -129,7 +165,7 @@ fn test_cow() { #[test] fn test_lifetimes() { #[derive(Deserialize)] - struct Cows<'a, 'b> { + pub struct Cows<'a, 'b> { _copied: Cow<'a, str>, #[serde(borrow)] @@ -145,7 +181,7 @@ fn test_lifetimes() { } #[derive(Deserialize)] - struct Wrap<'a, 'b> { + pub struct Wrap<'a, 'b> { #[serde(borrow = "'b")] _cows: Cows<'a, 'b>, } diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index 025d87b09..707c0c700 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -1,12 +1,29 @@ -#![allow(clippy::decimal_literal_representation, clippy::unreadable_literal)] +#![allow( + clippy::cast_lossless, + clippy::decimal_literal_representation, + clippy::derive_partial_eq_without_eq, + clippy::empty_enums, + clippy::manual_assert, + clippy::needless_pass_by_value, + clippy::uninlined_format_args, + clippy::unreadable_literal +)] #![cfg_attr(feature = "unstable", feature(never_type))] +use serde::de::value::{F32Deserializer, F64Deserializer}; +use serde::de::{Deserialize, DeserializeOwned, Deserializer, IntoDeserializer}; +use serde_derive::Deserialize; +use serde_test::{assert_de_tokens, Configure, Token}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::default::Default; use std::ffi::{CStr, CString, OsString}; use std::fmt::Debug; +use std::iter; use std::net; -use std::num::Wrapping; +use std::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Saturating, Wrapping, +}; use std::ops::Bound; use std::path::{Path, PathBuf}; use std::rc::{Rc, Weak as RcWeak}; @@ -14,16 +31,10 @@ use std::sync::atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8, AtomicUsize, Ordering, }; -use std::sync::{Arc, Weak as ArcWeak}; -use std::time::{Duration, UNIX_EPOCH}; - #[cfg(target_arch = "x86_64")] use std::sync::atomic::{AtomicI64, AtomicU64}; - -use fnv::FnvHasher; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Deserializer}; -use serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token}; +use std::sync::{Arc, Weak as ArcWeak}; +use std::time::{Duration, UNIX_EPOCH}; #[macro_use] mod macros; @@ -33,6 +44,9 @@ mod macros; #[derive(Copy, Clone, PartialEq, Debug, Deserialize)] struct UnitStruct; +#[derive(Copy, Clone, PartialEq, Debug, Deserialize)] +struct GenericUnitStruct; + #[derive(PartialEq, Debug, Deserialize)] struct NewtypeStruct(i32); @@ -47,14 +61,6 @@ struct Struct { c: i32, } -#[derive(PartialEq, Debug, Deserialize)] -#[serde(deny_unknown_fields)] -struct StructDenyUnknown { - a: i32, - #[serde(skip_deserializing)] - b: i32, -} - #[derive(PartialEq, Debug, Deserialize)] #[serde(default)] struct StructDefault { @@ -86,7 +92,7 @@ struct StructSkipDefault { #[derive(PartialEq, Debug, Deserialize)] #[serde(default)] -struct StructSkipDefaultGeneric { +pub struct StructSkipDefaultGeneric { #[serde(skip_deserializing)] t: T, } @@ -123,13 +129,6 @@ enum Enum { SimpleWithSkipped(#[serde(skip_deserializing)] NotDeserializable), } -#[derive(PartialEq, Debug, Deserialize)] -enum EnumSkipAll { - #[allow(dead_code)] - #[serde(skip_deserializing)] - Skipped, -} - #[derive(PartialEq, Debug, Deserialize)] enum EnumOther { Unit, @@ -152,54 +151,16 @@ impl<'de> Deserialize<'de> for IgnoredAny { ////////////////////////////////////////////////////////////////////////// -macro_rules! declare_tests { - ( - $readable:tt - $($name:ident { $($value:expr => $tokens:expr,)+ })+ - ) => { - $( - #[test] - fn $name() { - $( - // Test ser/de roundtripping - assert_de_tokens(&$value.$readable(), $tokens); - - // Test that the tokens are ignorable - assert_de_tokens_ignore($tokens); - )+ - } - )+ - }; - - ($( - $(#[$cfg:meta])* - $name:ident { $($value:expr => $tokens:expr,)+ } - )+) => { - $( - $(#[$cfg])* - #[test] - fn $name() { - $( - // Test ser/de roundtripping - assert_de_tokens(&$value, $tokens); - - // Test that the tokens are ignorable - assert_de_tokens_ignore($tokens); - )+ - } - )+ - } -} +#[track_caller] +fn test<'de, T>(value: T, tokens: &'de [Token]) +where + T: Deserialize<'de> + PartialEq + Debug, +{ + // Test ser/de roundtripping + assert_de_tokens(&value, tokens); -macro_rules! declare_error_tests { - ($($name:ident<$target:ty> { $tokens:expr, $expected:expr, })+) => { - $( - #[test] - fn $name() { - assert_de_tokens_error::<$target>($tokens, $expected); - } - )+ - } + // Test that the tokens are ignorable + assert_de_tokens_ignore(tokens); } #[derive(Debug)] @@ -223,6 +184,7 @@ impl PartialEq for SkipPartialEq { } } +#[track_caller] fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { #[derive(PartialEq, Debug, Deserialize)] struct IgnoreBase { @@ -238,872 +200,2108 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { Token::Str("ignored"), ] .into_iter() - .chain(ignorable_tokens.to_vec().into_iter()) - .chain(vec![Token::MapEnd].into_iter()) + .chain(ignorable_tokens.iter().copied()) + .chain(iter::once(Token::MapEnd)) .collect(); - let mut de = serde_test::Deserializer::new(&concated_tokens); - let base = IgnoreBase::deserialize(&mut de).unwrap(); - assert_eq!(base, IgnoreBase { a: 1 }); + let expected = IgnoreBase { a: 1 }; + assert_de_tokens(&expected, &concated_tokens); } ////////////////////////////////////////////////////////////////////////// -declare_tests! { - test_bool { - true => &[Token::Bool(true)], - false => &[Token::Bool(false)], - } - test_isize { - 0isize => &[Token::I8(0)], - 0isize => &[Token::I16(0)], - 0isize => &[Token::I32(0)], - 0isize => &[Token::I64(0)], - 0isize => &[Token::U8(0)], - 0isize => &[Token::U16(0)], - 0isize => &[Token::U32(0)], - 0isize => &[Token::U64(0)], - } - test_ints { - 0i8 => &[Token::I8(0)], - 0i16 => &[Token::I16(0)], - 0i32 => &[Token::I32(0)], - 0i64 => &[Token::I64(0)], - } - test_uints { - 0u8 => &[Token::U8(0)], - 0u16 => &[Token::U16(0)], - 0u32 => &[Token::U32(0)], - 0u64 => &[Token::U64(0)], - } - test_floats { - 0f32 => &[Token::F32(0.)], - 0f64 => &[Token::F64(0.)], - } - #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] - test_small_int_to_128 { - 1i128 => &[Token::I8(1)], - 1i128 => &[Token::I16(1)], - 1i128 => &[Token::I32(1)], - 1i128 => &[Token::I64(1)], - - 1i128 => &[Token::U8(1)], - 1i128 => &[Token::U16(1)], - 1i128 => &[Token::U32(1)], - 1i128 => &[Token::U64(1)], - - 1u128 => &[Token::I8(1)], - 1u128 => &[Token::I16(1)], - 1u128 => &[Token::I32(1)], - 1u128 => &[Token::I64(1)], - - 1u128 => &[Token::U8(1)], - 1u128 => &[Token::U16(1)], - 1u128 => &[Token::U32(1)], - 1u128 => &[Token::U64(1)], - } - test_char { - 'a' => &[Token::Char('a')], - 'a' => &[Token::Str("a")], - 'a' => &[Token::String("a")], - } - test_string { - "abc".to_owned() => &[Token::Str("abc")], - "abc".to_owned() => &[Token::String("abc")], - "a".to_owned() => &[Token::Char('a')], - } - test_option { - None:: => &[Token::Unit], - None:: => &[Token::None], - Some(1) => &[ - Token::Some, - Token::I32(1), - ], - } - test_result { - Ok::(0) => &[ +#[test] +fn test_bool() { + test(true, &[Token::Bool(true)]); + test(false, &[Token::Bool(false)]); +} + +#[test] +fn test_i8() { + let test = test::; + + // from signed + test(-128, &[Token::I8(-128)]); + test(-128, &[Token::I16(-128)]); + test(-128, &[Token::I32(-128)]); + test(-128, &[Token::I64(-128)]); + test(127, &[Token::I8(127)]); + test(127, &[Token::I16(127)]); + test(127, &[Token::I32(127)]); + test(127, &[Token::I64(127)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(127, &[Token::U8(127)]); + test(127, &[Token::U16(127)]); + test(127, &[Token::U32(127)]); + test(127, &[Token::U64(127)]); +} + +#[test] +fn test_i16() { + let test = test::; + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-32768, &[Token::I32(-32768)]); + test(-32768, &[Token::I64(-32768)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(32767, &[Token::I32(32767)]); + test(32767, &[Token::I64(32767)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(32767, &[Token::U16(32767)]); + test(32767, &[Token::U32(32767)]); + test(32767, &[Token::U64(32767)]); +} + +#[test] +fn test_i32() { + let test = test::; + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-2147483648, &[Token::I64(-2147483648)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(2147483647, &[Token::I64(2147483647)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(2147483647, &[Token::U32(2147483647)]); + test(2147483647, &[Token::U64(2147483647)]); +} + +#[test] +fn test_i64() { + let test = test::; + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-9223372036854775808, &[Token::I64(-9223372036854775808)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(9223372036854775807, &[Token::U64(9223372036854775807)]); +} + +#[test] +fn test_i128() { + let test = test::; + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-9223372036854775808, &[Token::I64(-9223372036854775808)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_isize() { + let test = test::; + + // from signed + test(-10, &[Token::I8(-10)]); + test(-10, &[Token::I16(-10)]); + test(-10, &[Token::I32(-10)]); + test(-10, &[Token::I64(-10)]); + test(10, &[Token::I8(10)]); + test(10, &[Token::I16(10)]); + test(10, &[Token::I32(10)]); + test(10, &[Token::I64(10)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(10, &[Token::U8(10)]); + test(10, &[Token::U16(10)]); + test(10, &[Token::U32(10)]); + test(10, &[Token::U64(10)]); +} + +#[test] +fn test_u8() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(127, &[Token::I8(127)]); + test(255, &[Token::I16(255)]); + test(255, &[Token::I32(255)]); + test(255, &[Token::I64(255)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(255, &[Token::U16(255)]); + test(255, &[Token::U32(255)]); + test(255, &[Token::U64(255)]); +} + +#[test] +fn test_u16() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(65535, &[Token::I32(65535)]); + test(65535, &[Token::I64(65535)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(65535, &[Token::U32(65535)]); + test(65535, &[Token::U64(65535)]); +} + +#[test] +fn test_u32() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(4294967295, &[Token::I64(4294967295)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(4294967295, &[Token::U64(4294967295)]); +} + +#[test] +fn test_u64() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_u128() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_usize() { + let test = test::; + + // from signed + test(0, &[Token::I8(0)]); + test(0, &[Token::I16(0)]); + test(0, &[Token::I32(0)]); + test(0, &[Token::I64(0)]); + test(10, &[Token::I8(10)]); + test(10, &[Token::I16(10)]); + test(10, &[Token::I32(10)]); + test(10, &[Token::I64(10)]); + + // from unsigned + test(0, &[Token::U8(0)]); + test(0, &[Token::U16(0)]); + test(0, &[Token::U32(0)]); + test(0, &[Token::U64(0)]); + test(10, &[Token::U8(10)]); + test(10, &[Token::U16(10)]); + test(10, &[Token::U32(10)]); + test(10, &[Token::U64(10)]); +} + +#[test] +fn test_nonzero_i8() { + let test = |value, tokens| test(NonZeroI8::new(value).unwrap(), tokens); + + // from signed + test(-128, &[Token::I8(-128)]); + test(-128, &[Token::I16(-128)]); + test(-128, &[Token::I32(-128)]); + test(-128, &[Token::I64(-128)]); + test(127, &[Token::I8(127)]); + test(127, &[Token::I16(127)]); + test(127, &[Token::I32(127)]); + test(127, &[Token::I64(127)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(127, &[Token::U8(127)]); + test(127, &[Token::U16(127)]); + test(127, &[Token::U32(127)]); + test(127, &[Token::U64(127)]); +} + +#[test] +fn test_nonzero_i16() { + let test = |value, tokens| test(NonZeroI16::new(value).unwrap(), tokens); + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-32768, &[Token::I32(-32768)]); + test(-32768, &[Token::I64(-32768)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(32767, &[Token::I32(32767)]); + test(32767, &[Token::I64(32767)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(32767, &[Token::U16(32767)]); + test(32767, &[Token::U32(32767)]); + test(32767, &[Token::U64(32767)]); +} + +#[test] +fn test_nonzero_i32() { + let test = |value, tokens| test(NonZeroI32::new(value).unwrap(), tokens); + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-2147483648, &[Token::I64(-2147483648)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(2147483647, &[Token::I64(2147483647)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(2147483647, &[Token::U32(2147483647)]); + test(2147483647, &[Token::U64(2147483647)]); +} + +#[test] +fn test_nonzero_i64() { + let test = |value, tokens| test(NonZeroI64::new(value).unwrap(), tokens); + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-9223372036854775808, &[Token::I64(-9223372036854775808)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(9223372036854775807, &[Token::U64(9223372036854775807)]); +} + +#[test] +fn test_nonzero_i128() { + let test = |value, tokens| test(NonZeroI128::new(value).unwrap(), tokens); + + // from signed + test(-128, &[Token::I8(-128)]); + test(-32768, &[Token::I16(-32768)]); + test(-2147483648, &[Token::I32(-2147483648)]); + test(-9223372036854775808, &[Token::I64(-9223372036854775808)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_nonzero_isize() { + let test = |value, tokens| test(NonZeroIsize::new(value).unwrap(), tokens); + + // from signed + test(-10, &[Token::I8(-10)]); + test(-10, &[Token::I16(-10)]); + test(-10, &[Token::I32(-10)]); + test(-10, &[Token::I64(-10)]); + test(10, &[Token::I8(10)]); + test(10, &[Token::I16(10)]); + test(10, &[Token::I32(10)]); + test(10, &[Token::I64(10)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(10, &[Token::U8(10)]); + test(10, &[Token::U16(10)]); + test(10, &[Token::U32(10)]); + test(10, &[Token::U64(10)]); +} + +#[test] +fn test_nonzero_u8() { + let test = |value, tokens| test(NonZeroU8::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(127, &[Token::I8(127)]); + test(255, &[Token::I16(255)]); + test(255, &[Token::I32(255)]); + test(255, &[Token::I64(255)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(255, &[Token::U16(255)]); + test(255, &[Token::U32(255)]); + test(255, &[Token::U64(255)]); +} + +#[test] +fn test_nonzero_u16() { + let test = |value, tokens| test(NonZeroU16::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(65535, &[Token::I32(65535)]); + test(65535, &[Token::I64(65535)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(65535, &[Token::U32(65535)]); + test(65535, &[Token::U64(65535)]); +} + +#[test] +fn test_nonzero_u32() { + let test = |value, tokens| test(NonZeroU32::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(4294967295, &[Token::I64(4294967295)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(4294967295, &[Token::U64(4294967295)]); +} + +#[test] +fn test_nonzero_u64() { + let test = |value, tokens| test(NonZeroU64::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_nonzero_u128() { + let test = |value, tokens| test(NonZeroU128::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(127, &[Token::I8(127)]); + test(32767, &[Token::I16(32767)]); + test(2147483647, &[Token::I32(2147483647)]); + test(9223372036854775807, &[Token::I64(9223372036854775807)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(255, &[Token::U8(255)]); + test(65535, &[Token::U16(65535)]); + test(4294967295, &[Token::U32(4294967295)]); + test(18446744073709551615, &[Token::U64(18446744073709551615)]); +} + +#[test] +fn test_nonzero_usize() { + let test = |value, tokens| test(NonZeroUsize::new(value).unwrap(), tokens); + + // from signed + test(1, &[Token::I8(1)]); + test(1, &[Token::I16(1)]); + test(1, &[Token::I32(1)]); + test(1, &[Token::I64(1)]); + test(10, &[Token::I8(10)]); + test(10, &[Token::I16(10)]); + test(10, &[Token::I32(10)]); + test(10, &[Token::I64(10)]); + + // from unsigned + test(1, &[Token::U8(1)]); + test(1, &[Token::U16(1)]); + test(1, &[Token::U32(1)]); + test(1, &[Token::U64(1)]); + test(10, &[Token::U8(10)]); + test(10, &[Token::U16(10)]); + test(10, &[Token::U32(10)]); + test(10, &[Token::U64(10)]); +} + +#[test] +fn test_f32() { + let test = test::; + + test(1.11, &[Token::F32(1.11)]); + test(1.11, &[Token::F64(1.11)]); +} + +#[test] +fn test_f64() { + let test = test::; + + test(1.11f32 as f64, &[Token::F32(1.11)]); + test(1.11, &[Token::F64(1.11)]); +} + +#[test] +fn test_nan() { + let f32_deserializer = F32Deserializer::::new; + let f64_deserializer = F64Deserializer::::new; + + let pos_f32_nan = f32_deserializer(f32::NAN.copysign(1.0)); + let pos_f64_nan = f64_deserializer(f64::NAN.copysign(1.0)); + assert!(f32::deserialize(pos_f32_nan).unwrap().is_sign_positive()); + assert!(f32::deserialize(pos_f64_nan).unwrap().is_sign_positive()); + assert!(f64::deserialize(pos_f32_nan).unwrap().is_sign_positive()); + assert!(f64::deserialize(pos_f64_nan).unwrap().is_sign_positive()); + + let neg_f32_nan = f32_deserializer(f32::NAN.copysign(-1.0)); + let neg_f64_nan = f64_deserializer(f64::NAN.copysign(-1.0)); + assert!(f32::deserialize(neg_f32_nan).unwrap().is_sign_negative()); + assert!(f32::deserialize(neg_f64_nan).unwrap().is_sign_negative()); + assert!(f64::deserialize(neg_f32_nan).unwrap().is_sign_negative()); + assert!(f64::deserialize(neg_f64_nan).unwrap().is_sign_negative()); +} + +#[test] +fn test_char() { + test('a', &[Token::Char('a')]); + test('a', &[Token::Str("a")]); + test('a', &[Token::String("a")]); +} + +#[test] +fn test_string() { + test("abc".to_owned(), &[Token::Str("abc")]); + test("abc".to_owned(), &[Token::String("abc")]); + test("a".to_owned(), &[Token::Char('a')]); +} + +#[test] +fn test_option() { + test(None::, &[Token::Unit]); + test(None::, &[Token::None]); + test(Some(1), &[Token::Some, Token::I32(1)]); +} + +#[test] +fn test_result() { + test( + Ok::(0), + &[ Token::Enum { name: "Result" }, Token::Str("Ok"), Token::I32(0), ], - Err::(1) => &[ + ); + test( + Err::(1), + &[ Token::Enum { name: "Result" }, Token::Str("Err"), Token::I32(1), ], - } - test_unit { - () => &[Token::Unit], - } - test_unit_struct { - UnitStruct => &[Token::Unit], - UnitStruct => &[ - Token::UnitStruct { name: "UnitStruct" }, - ], - } - test_newtype_struct { - NewtypeStruct(1) => &[ - Token::NewtypeStruct { name: "NewtypeStruct" }, + ); +} + +#[test] +fn test_unit() { + test((), &[Token::Unit]); +} + +#[test] +fn test_unit_struct() { + test(UnitStruct, &[Token::Unit]); + test(UnitStruct, &[Token::UnitStruct { name: "UnitStruct" }]); +} + +#[test] +fn test_generic_unit_struct() { + test(GenericUnitStruct::<8>, &[Token::Unit]); + test( + GenericUnitStruct::<8>, + &[Token::UnitStruct { + name: "GenericUnitStruct", + }], + ); +} + +#[test] +fn test_newtype_struct() { + test( + NewtypeStruct(1), + &[ + Token::NewtypeStruct { + name: "NewtypeStruct", + }, Token::I32(1), ], - } - test_tuple_struct { - TupleStruct(1, 2, 3) => &[ + ); +} + +#[test] +fn test_tuple_struct() { + test( + TupleStruct(1, 2, 3), + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - TupleStruct(1, 2, 3) => &[ + ); + test( + TupleStruct(1, 2, 3), + &[ Token::Seq { len: None }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - TupleStruct(1, 2, 3) => &[ - Token::TupleStruct { name: "TupleStruct", len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + ); + test( + TupleStruct(1, 2, 3), + &[ + Token::TupleStruct { + name: "TupleStruct", + len: 3, + }, + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleStructEnd, ], - TupleStruct(1, 2, 3) => &[ - Token::TupleStruct { name: "TupleStruct", len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + ); + test( + TupleStruct(1, 2, 3), + &[ + Token::TupleStruct { + name: "TupleStruct", + len: 3, + }, + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleStructEnd, ], - } - test_btreeset { - BTreeSet::::new() => &[ + ); +} + +#[test] +fn test_btreeset() { + test( + BTreeSet::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + test( + btreeset![btreeset![], btreeset![1], btreeset![2, 3]], + &[ + Token::Seq { len: Some(3) }, Token::Seq { len: Some(0) }, Token::SeqEnd, - ], - btreeset![btreeset![], btreeset![1], btreeset![2, 3]] => &[ - Token::Seq { len: Some(3) }, - Token::Seq { len: Some(0) }, - Token::SeqEnd, - - Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, - - Token::Seq { len: Some(2) }, - Token::I32(2), - Token::I32(3), - Token::SeqEnd, + Token::Seq { len: Some(1) }, + Token::I32(1), + Token::SeqEnd, + Token::Seq { len: Some(2) }, + Token::I32(2), + Token::I32(3), + Token::SeqEnd, Token::SeqEnd, ], - BTreeSet::::new() => &[ - Token::TupleStruct { name: "Anything", len: 0 }, + ); + test( + BTreeSet::::new(), + &[ + Token::TupleStruct { + name: "Anything", + len: 0, + }, Token::TupleStructEnd, ], - } - test_hashset { - HashSet::::new() => &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ], - hashset![1, 2, 3] => &[ + ); +} + +#[test] +fn test_hashset() { + test( + HashSet::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + test( + hashset![1, 2, 3], + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - HashSet::::new() => &[ - Token::TupleStruct { name: "Anything", len: 0 }, + ); + test( + HashSet::::new(), + &[ + Token::TupleStruct { + name: "Anything", + len: 0, + }, Token::TupleStructEnd, ], - hashset![FnvHasher @ 1, 2, 3] => &[ + ); + test( + hashset![foldhash::fast::FixedState; 1, 2, 3], + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), - Token::SeqEnd, - ], - } - test_vec { - Vec::::new() => &[ - Token::Seq { len: Some(0) }, + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - vec![vec![], vec![1], vec![2, 3]] => &[ - Token::Seq { len: Some(3) }, - Token::Seq { len: Some(0) }, - Token::SeqEnd, + ); +} - Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, +#[test] +fn test_vec() { + test( + Vec::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); - Token::Seq { len: Some(2) }, - Token::I32(2), - Token::I32(3), - Token::SeqEnd, + test( + vec![vec![], vec![1], vec![2, 3]], + &[ + Token::Seq { len: Some(3) }, + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::Seq { len: Some(1) }, + Token::I32(1), + Token::SeqEnd, + Token::Seq { len: Some(2) }, + Token::I32(2), + Token::I32(3), + Token::SeqEnd, Token::SeqEnd, ], - Vec::::new() => &[ - Token::TupleStruct { name: "Anything", len: 0 }, + ); + test( + Vec::::new(), + &[ + Token::TupleStruct { + name: "Anything", + len: 0, + }, Token::TupleStructEnd, ], - } - test_array { - [0; 0] => &[ + ); +} + +#[test] +fn test_array() { + test([0; 0], &[Token::Seq { len: Some(0) }, Token::SeqEnd]); + test([0; 0], &[Token::Tuple { len: 0 }, Token::TupleEnd]); + test( + ([0; 0], [1], [2, 3]), + &[ + Token::Seq { len: Some(3) }, Token::Seq { len: Some(0) }, Token::SeqEnd, + Token::Seq { len: Some(1) }, + Token::I32(1), + Token::SeqEnd, + Token::Seq { len: Some(2) }, + Token::I32(2), + Token::I32(3), + Token::SeqEnd, + Token::SeqEnd, ], - [0; 0] => &[ + ); + test( + ([0; 0], [1], [2, 3]), + &[ + Token::Tuple { len: 3 }, Token::Tuple { len: 0 }, Token::TupleEnd, - ], - ([0; 0], [1], [2, 3]) => &[ - Token::Seq { len: Some(3) }, - Token::Seq { len: Some(0) }, - Token::SeqEnd, - - Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, - - Token::Seq { len: Some(2) }, - Token::I32(2), - Token::I32(3), - Token::SeqEnd, - Token::SeqEnd, - ], - ([0; 0], [1], [2, 3]) => &[ - Token::Tuple { len: 3 }, - Token::Tuple { len: 0 }, - Token::TupleEnd, - - Token::Tuple { len: 1 }, - Token::I32(1), - Token::TupleEnd, - - Token::Tuple { len: 2 }, - Token::I32(2), - Token::I32(3), - Token::TupleEnd, + Token::Tuple { len: 1 }, + Token::I32(1), + Token::TupleEnd, + Token::Tuple { len: 2 }, + Token::I32(2), + Token::I32(3), + Token::TupleEnd, Token::TupleEnd, ], - [0; 0] => &[ - Token::TupleStruct { name: "Anything", len: 0 }, + ); + test( + [0; 0], + &[ + Token::TupleStruct { + name: "Anything", + len: 0, + }, Token::TupleStructEnd, ], - } - test_tuple { - (1,) => &[ - Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, - ], - (1, 2, 3) => &[ + ); +} + +#[test] +fn test_tuple() { + test( + (1,), + &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], + ); + test( + (1, 2, 3), + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - (1,) => &[ - Token::Tuple { len: 1 }, - Token::I32(1), - Token::TupleEnd, - ], - (1, 2, 3) => &[ + ); + test( + (1,), + &[Token::Tuple { len: 1 }, Token::I32(1), Token::TupleEnd], + ); + test( + (1, 2, 3), + &[ Token::Tuple { len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleEnd, ], - } - test_btreemap { - BTreeMap::::new() => &[ - Token::Map { len: Some(0) }, - Token::MapEnd, - ], - btreemap![1 => 2] => &[ + ); +} + +#[test] +fn test_btreemap() { + test( + BTreeMap::::new(), + &[Token::Map { len: Some(0) }, Token::MapEnd], + ); + test( + btreemap![1 => 2], + &[ Token::Map { len: Some(1) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::MapEnd, ], - btreemap![1 => 2, 3 => 4] => &[ + ); + test( + btreemap![1 => 2, 3 => 4], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::I32(2), - - Token::I32(3), - Token::I32(4), + Token::I32(1), + Token::I32(2), + Token::I32(3), + Token::I32(4), Token::MapEnd, ], - btreemap![1 => btreemap![], 2 => btreemap![3 => 4, 5 => 6]] => &[ + ); + test( + btreemap![1 => btreemap![], 2 => btreemap![3 => 4, 5 => 6]], + &[ + Token::Map { len: Some(2) }, + Token::I32(1), + Token::Map { len: Some(0) }, + Token::MapEnd, + Token::I32(2), Token::Map { len: Some(2) }, - Token::I32(1), - Token::Map { len: Some(0) }, - Token::MapEnd, - - Token::I32(2), - Token::Map { len: Some(2) }, - Token::I32(3), - Token::I32(4), - - Token::I32(5), - Token::I32(6), - Token::MapEnd, + Token::I32(3), + Token::I32(4), + Token::I32(5), + Token::I32(6), + Token::MapEnd, Token::MapEnd, ], - BTreeMap::::new() => &[ - Token::Struct { name: "Anything", len: 0 }, + ); + test( + BTreeMap::::new(), + &[ + Token::Struct { + name: "Anything", + len: 0, + }, Token::StructEnd, ], - } - test_hashmap { - HashMap::::new() => &[ - Token::Map { len: Some(0) }, - Token::MapEnd, - ], - hashmap![1 => 2] => &[ + ); +} + +#[test] +fn test_hashmap() { + test( + HashMap::::new(), + &[Token::Map { len: Some(0) }, Token::MapEnd], + ); + test( + hashmap![1 => 2], + &[ Token::Map { len: Some(1) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::MapEnd, ], - hashmap![1 => 2, 3 => 4] => &[ + ); + test( + hashmap![1 => 2, 3 => 4], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::I32(2), - - Token::I32(3), - Token::I32(4), + Token::I32(1), + Token::I32(2), + Token::I32(3), + Token::I32(4), Token::MapEnd, ], - hashmap![1 => hashmap![], 2 => hashmap![3 => 4, 5 => 6]] => &[ + ); + test( + hashmap![1 => hashmap![], 2 => hashmap![3 => 4, 5 => 6]], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::Map { len: Some(0) }, - Token::MapEnd, - - Token::I32(2), - Token::Map { len: Some(2) }, - Token::I32(3), - Token::I32(4), - - Token::I32(5), - Token::I32(6), - Token::MapEnd, + Token::I32(1), + Token::Map { len: Some(0) }, + Token::MapEnd, + Token::I32(2), + Token::Map { len: Some(2) }, + Token::I32(3), + Token::I32(4), + Token::I32(5), + Token::I32(6), + Token::MapEnd, Token::MapEnd, ], - HashMap::::new() => &[ - Token::Struct { name: "Anything", len: 0 }, + ); + test( + HashMap::::new(), + &[ + Token::Struct { + name: "Anything", + len: 0, + }, Token::StructEnd, ], - hashmap![FnvHasher @ 1 => 2, 3 => 4] => &[ + ); + test( + hashmap![foldhash::fast::FixedState; 1 => 2, 3 => 4], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), + Token::I32(3), + Token::I32(4), + Token::MapEnd, + ], + ); +} - Token::I32(3), - Token::I32(4), +#[test] +fn test_struct() { + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), Token::MapEnd, ], - } - test_struct { - Struct { a: 1, b: 2, c: 0 } => &[ + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ Token::Map { len: Some(3) }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), + Token::U8(0), + Token::I32(1), + Token::U8(1), + Token::I32(2), Token::MapEnd, ], - Struct { a: 1, b: 2, c: 0 } => &[ + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ Token::Map { len: Some(3) }, - Token::U32(0), - Token::I32(1), - - Token::U32(1), - Token::I32(2), + Token::U16(0), + Token::I32(1), + Token::U16(1), + Token::I32(2), Token::MapEnd, ], - Struct { a: 1, b: 2, c: 0 } => &[ - Token::Struct { name: "Struct", len: 2 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::U32(0), + Token::I32(1), + Token::U32(1), + Token::I32(2), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::U64(0), + Token::I32(1), + Token::U64(1), + Token::I32(2), + Token::MapEnd, + ], + ); + // Mixed key types + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + Token::U64(1), + Token::I32(2), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), Token::StructEnd, ], - Struct { a: 1, b: 2, c: 0 } => &[ + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::SeqEnd, ], - } - test_struct_with_skip { - Struct { a: 1, b: 2, c: 0 } => &[ - Token::Map { len: Some(3) }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), - - Token::Str("c"), - Token::I32(3), + ); +} - Token::Str("d"), - Token::I32(4), +#[test] +fn test_struct_borrowed_keys() { + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::BorrowedStr("a"), + Token::I32(1), + Token::BorrowedStr("b"), + Token::I32(2), Token::MapEnd, ], - Struct { a: 1, b: 2, c: 0 } => &[ - Token::Struct { name: "Struct", len: 2 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), - - Token::Str("c"), - Token::I32(3), + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::BorrowedStr("a"), + Token::I32(1), + Token::BorrowedStr("b"), + Token::I32(2), + Token::StructEnd, + ], + ); +} - Token::Str("d"), - Token::I32(4), +#[test] +fn test_struct_owned_keys() { + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::String("a"), + Token::I32(1), + Token::String("b"), + Token::I32(2), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::String("a"), + Token::I32(1), + Token::String("b"), + Token::I32(2), Token::StructEnd, ], - } - test_struct_skip_all { - StructSkipAll { a: 0 } => &[ - Token::Struct { name: "StructSkipAll", len: 0 }, + ); +} + +#[test] +fn test_struct_with_skip() { + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::Str("c"), + Token::I32(3), + Token::Str("d"), + Token::I32(4), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + Token::U16(1), + Token::I32(2), + Token::U32(2), + Token::I32(3), + Token::U64(3), + Token::I32(4), + Token::MapEnd, + ], + ); + test( + Struct { a: 1, b: 2, c: 0 }, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::Str("c"), + Token::I32(3), + Token::Str("d"), + Token::I32(4), Token::StructEnd, ], - StructSkipAll { a: 0 } => &[ - Token::Struct { name: "StructSkipAll", len: 0 }, - Token::Str("a"), - Token::I32(1), + ); +} - Token::Str("b"), - Token::I32(2), +#[test] +fn test_struct_skip_all() { + test( + StructSkipAll { a: 0 }, + &[ + Token::Struct { + name: "StructSkipAll", + len: 0, + }, Token::StructEnd, ], - } - test_struct_skip_default { - StructSkipDefault { a: 16 } => &[ - Token::Struct { name: "StructSkipDefault", len: 0 }, + ); + test( + StructSkipAll { a: 0 }, + &[ + Token::Struct { + name: "StructSkipAll", + len: 0, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), Token::StructEnd, ], - } - test_struct_skip_all_deny_unknown { - StructSkipAllDenyUnknown { a: 0 } => &[ - Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 }, + ); +} + +#[test] +fn test_struct_skip_default() { + test( + StructSkipDefault { a: 16 }, + &[ + Token::Struct { + name: "StructSkipDefault", + len: 0, + }, Token::StructEnd, ], - } - test_struct_default { - StructDefault { a: 50, b: "overwritten".to_string() } => &[ - Token::Struct { name: "StructDefault", len: 2 }, - Token::Str("a"), - Token::I32(50), - - Token::Str("b"), - Token::String("overwritten"), + ); +} + +#[test] +fn test_struct_skip_all_deny_unknown() { + test( + StructSkipAllDenyUnknown { a: 0 }, + &[ + Token::Struct { + name: "StructSkipAllDenyUnknown", + len: 0, + }, Token::StructEnd, ], - StructDefault { a: 100, b: "default".to_string() } => &[ - Token::Struct { name: "StructDefault", len: 2 }, + ); +} + +#[test] +fn test_struct_default() { + test( + StructDefault { + a: 50, + b: "overwritten".to_string(), + }, + &[ + Token::Struct { + name: "StructDefault", + len: 2, + }, + Token::Str("a"), + Token::I32(50), + Token::Str("b"), + Token::String("overwritten"), Token::StructEnd, ], - } - test_enum_unit { - Enum::Unit => &[ - Token::UnitVariant { name: "Enum", variant: "Unit" }, + ); + test( + StructDefault { + a: 100, + b: "default".to_string(), + }, + &[ + Token::Struct { + name: "StructDefault", + len: 2, + }, + Token::StructEnd, ], - } - test_enum_simple { - Enum::Simple(1) => &[ - Token::NewtypeVariant { name: "Enum", variant: "Simple" }, + ); +} + +#[test] +fn test_enum_unit() { + test( + Enum::Unit, + &[Token::UnitVariant { + name: "Enum", + variant: "Unit", + }], + ); +} + +#[test] +fn test_enum_simple() { + test( + Enum::Simple(1), + &[ + Token::NewtypeVariant { + name: "Enum", + variant: "Simple", + }, Token::I32(1), ], - } - test_enum_simple_with_skipped { - Enum::SimpleWithSkipped(NotDeserializable) => &[ - Token::UnitVariant { name: "Enum", variant: "SimpleWithSkipped" }, - ], - } - test_enum_seq { - Enum::Seq(1, 2, 3) => &[ - Token::TupleVariant { name: "Enum", variant: "Seq", len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + ); +} + +#[test] +fn test_enum_simple_with_skipped() { + test( + Enum::SimpleWithSkipped(NotDeserializable), + &[Token::UnitVariant { + name: "Enum", + variant: "SimpleWithSkipped", + }], + ); +} + +#[test] +fn test_enum_seq() { + test( + Enum::Seq(1, 2, 3), + &[ + Token::TupleVariant { + name: "Enum", + variant: "Seq", + len: 3, + }, + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleVariantEnd, ], - } - test_enum_map { - Enum::Map { a: 1, b: 2, c: 3 } => &[ - Token::StructVariant { name: "Enum", variant: "Map", len: 3 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), + ); +} - Token::Str("c"), - Token::I32(3), +#[test] +fn test_enum_map() { + test( + Enum::Map { a: 1, b: 2, c: 3 }, + &[ + Token::StructVariant { + name: "Enum", + variant: "Map", + len: 3, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::Str("c"), + Token::I32(3), Token::StructVariantEnd, ], - } - test_enum_unit_usize { - Enum::Unit => &[ - Token::Enum { name: "Enum" }, - Token::U32(0), - Token::Unit, - ], - } - test_enum_unit_bytes { - Enum::Unit => &[ + ); +} + +#[test] +fn test_enum_unit_usize() { + test( + Enum::Unit, + &[Token::Enum { name: "Enum" }, Token::U32(0), Token::Unit], + ); +} + +#[test] +fn test_enum_unit_bytes() { + test( + Enum::Unit, + &[ Token::Enum { name: "Enum" }, Token::Bytes(b"Unit"), Token::Unit, ], - } - test_enum_other_unit { - EnumOther::Unit => &[ + ); +} + +#[test] +fn test_enum_other_unit() { + test( + EnumOther::Unit, + &[ Token::Enum { name: "EnumOther" }, Token::Str("Unit"), Token::Unit, ], - } - test_enum_other { - EnumOther::Other => &[ + ); + test( + EnumOther::Unit, + &[Token::Enum { name: "EnumOther" }, Token::U8(0), Token::Unit], + ); + test( + EnumOther::Unit, + &[ + Token::Enum { name: "EnumOther" }, + Token::U16(0), + Token::Unit, + ], + ); + test( + EnumOther::Unit, + &[ + Token::Enum { name: "EnumOther" }, + Token::U32(0), + Token::Unit, + ], + ); + test( + EnumOther::Unit, + &[ + Token::Enum { name: "EnumOther" }, + Token::U64(0), + Token::Unit, + ], + ); +} + +#[test] +fn test_enum_other() { + test( + EnumOther::Other, + &[ Token::Enum { name: "EnumOther" }, Token::Str("Foo"), Token::Unit, ], - } - test_box { - Box::new(0i32) => &[Token::I32(0)], - } - test_boxed_slice { - Box::new([0, 1, 2]) => &[ + ); + test( + EnumOther::Other, + &[ + Token::Enum { name: "EnumOther" }, + Token::U8(42), + Token::Unit, + ], + ); + test( + EnumOther::Other, + &[ + Token::Enum { name: "EnumOther" }, + Token::U16(42), + Token::Unit, + ], + ); + test( + EnumOther::Other, + &[ + Token::Enum { name: "EnumOther" }, + Token::U32(42), + Token::Unit, + ], + ); + test( + EnumOther::Other, + &[ + Token::Enum { name: "EnumOther" }, + Token::U64(42), + Token::Unit, + ], + ); +} + +#[test] +fn test_box() { + test(Box::new(0i32), &[Token::I32(0)]); +} + +#[test] +fn test_boxed_slice() { + test( + Box::new([0, 1, 2]), + &[ Token::Seq { len: Some(3) }, Token::I32(0), Token::I32(1), Token::I32(2), Token::SeqEnd, ], - } - test_duration { - Duration::new(1, 2) => &[ - Token::Struct { name: "Duration", len: 2 }, - Token::Str("secs"), - Token::U64(1), - - Token::Str("nanos"), - Token::U32(2), + ); +} + +#[test] +fn test_duration() { + test( + Duration::new(1, 2), + &[ + Token::Struct { + name: "Duration", + len: 2, + }, + Token::Str("secs"), + Token::U64(1), + Token::Str("nanos"), + Token::U32(2), Token::StructEnd, ], - Duration::new(1, 2) => &[ + ); + test( + Duration::new(1, 2), + &[ Token::Seq { len: Some(2) }, - Token::I64(1), - Token::I64(2), + Token::I64(1), + Token::I64(2), Token::SeqEnd, ], - } - test_system_time { - UNIX_EPOCH + Duration::new(1, 2) => &[ - Token::Struct { name: "SystemTime", len: 2 }, - Token::Str("secs_since_epoch"), - Token::U64(1), - - Token::Str("nanos_since_epoch"), - Token::U32(2), + ); +} + +#[test] +fn test_system_time() { + test( + UNIX_EPOCH + Duration::new(1, 2), + &[ + Token::Struct { + name: "SystemTime", + len: 2, + }, + Token::Str("secs_since_epoch"), + Token::U64(1), + Token::Str("nanos_since_epoch"), + Token::U32(2), Token::StructEnd, ], - UNIX_EPOCH + Duration::new(1, 2) => &[ + ); + test( + UNIX_EPOCH + Duration::new(1, 2), + &[ Token::Seq { len: Some(2) }, - Token::I64(1), - Token::I64(2), + Token::I64(1), + Token::I64(2), Token::SeqEnd, ], - } - test_range { - 1u32..2u32 => &[ - Token::Struct { name: "Range", len: 2 }, - Token::Str("start"), - Token::U32(1), - - Token::Str("end"), - Token::U32(2), + ); +} + +#[test] +fn test_range() { + test( + 1u32..2u32, + &[ + Token::Struct { + name: "Range", + len: 2, + }, + Token::Str("start"), + Token::U32(1), + Token::Str("end"), + Token::U32(2), Token::StructEnd, ], - 1u32..2u32 => &[ + ); + test( + 1u32..2u32, + &[ Token::Seq { len: Some(2) }, - Token::U64(1), - Token::U64(2), + Token::U64(1), + Token::U64(2), Token::SeqEnd, ], - } - test_range_inclusive { - 1u32..=2u32 => &[ - Token::Struct { name: "RangeInclusive", len: 2 }, - Token::Str("start"), - Token::U32(1), - - Token::Str("end"), - Token::U32(2), + ); +} + +#[test] +fn test_range_inclusive() { + test( + 1u32..=2u32, + &[ + Token::Struct { + name: "RangeInclusive", + len: 2, + }, + Token::Str("start"), + Token::U32(1), + Token::Str("end"), + Token::U32(2), Token::StructEnd, ], - 1u32..=2u32 => &[ + ); + test( + 1u32..=2u32, + &[ Token::Seq { len: Some(2) }, - Token::U64(1), - Token::U64(2), + Token::U64(1), + Token::U64(2), Token::SeqEnd, ], - } - test_bound { - Bound::Unbounded::<()> => &[ + ); +} + +#[test] +fn test_range_from() { + test( + 1u32.., + &[ + Token::Struct { + name: "RangeFrom", + len: 1, + }, + Token::Str("start"), + Token::U32(1), + Token::StructEnd, + ], + ); + test( + 1u32.., + &[Token::Seq { len: Some(1) }, Token::U32(1), Token::SeqEnd], + ); +} + +#[test] +fn test_range_to() { + test( + ..2u32, + &[ + Token::Struct { + name: "RangeTo", + len: 1, + }, + Token::Str("end"), + Token::U32(2), + Token::StructEnd, + ], + ); + test( + ..2u32, + &[Token::Seq { len: Some(1) }, Token::U32(2), Token::SeqEnd], + ); +} + +#[test] +fn test_bound() { + test( + Bound::Unbounded::<()>, + &[ Token::Enum { name: "Bound" }, Token::Str("Unbounded"), Token::Unit, ], - Bound::Included(0) => &[ + ); + test( + Bound::Included(0), + &[ Token::Enum { name: "Bound" }, Token::Str("Included"), Token::U8(0), ], - Bound::Excluded(0) => &[ + ); + test( + Bound::Excluded(0), + &[ Token::Enum { name: "Bound" }, Token::Str("Excluded"), Token::U8(0), ], + ); +} + +#[test] +fn test_path() { + test( + Path::new("/usr/local/lib"), + &[Token::BorrowedStr("/usr/local/lib")], + ); + test( + Path::new("/usr/local/lib"), + &[Token::BorrowedBytes(b"/usr/local/lib")], + ); +} + +#[test] +fn test_path_buf() { + test( + PathBuf::from("/usr/local/lib"), + &[Token::Str("/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib"), + &[Token::String("/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib"), + &[Token::Bytes(b"/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib"), + &[Token::ByteBuf(b"/usr/local/lib")], + ); +} + +#[test] +fn test_boxed_path() { + test( + PathBuf::from("/usr/local/lib").into_boxed_path(), + &[Token::Str("/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib").into_boxed_path(), + &[Token::String("/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib").into_boxed_path(), + &[Token::Bytes(b"/usr/local/lib")], + ); + test( + PathBuf::from("/usr/local/lib").into_boxed_path(), + &[Token::ByteBuf(b"/usr/local/lib")], + ); +} + +#[test] +fn test_cstring() { + test(CString::new("abc").unwrap(), &[Token::Bytes(b"abc")]); +} + +#[test] +fn test_rc() { + test(Rc::new(true), &[Token::Bool(true)]); +} + +#[test] +fn test_rc_weak_some() { + test( + SkipPartialEq(RcWeak::::new()), + &[Token::Some, Token::Bool(true)], + ); +} + +#[test] +fn test_rc_weak_none() { + test(SkipPartialEq(RcWeak::::new()), &[Token::None]); +} + +#[test] +fn test_arc() { + test(Arc::new(true), &[Token::Bool(true)]); +} + +#[test] +fn test_arc_weak_some() { + test( + SkipPartialEq(ArcWeak::::new()), + &[Token::Some, Token::Bool(true)], + ); +} + +#[test] +fn test_arc_weak_none() { + test(SkipPartialEq(ArcWeak::::new()), &[Token::None]); +} + +#[test] +fn test_wrapping() { + test(Wrapping(1usize), &[Token::U32(1)]); + test(Wrapping(1usize), &[Token::U64(1)]); +} + +#[test] +fn test_saturating() { + test(Saturating(1usize), &[Token::U32(1)]); + test(Saturating(1usize), &[Token::U64(1)]); + test(Saturating(0u8), &[Token::I8(0)]); + test(Saturating(0u16), &[Token::I16(0)]); + + // saturate input values at the minimum or maximum value + test(Saturating(u8::MAX), &[Token::U16(u16::MAX)]); + test(Saturating(u8::MAX), &[Token::U16(u8::MAX as u16 + 1)]); + test(Saturating(u16::MAX), &[Token::U32(u32::MAX)]); + test(Saturating(u32::MAX), &[Token::U64(u64::MAX)]); + test(Saturating(u8::MIN), &[Token::I8(i8::MIN)]); + test(Saturating(u16::MIN), &[Token::I16(i16::MIN)]); + test(Saturating(u32::MIN), &[Token::I32(i32::MIN)]); + test(Saturating(i8::MIN), &[Token::I16(i16::MIN)]); + test(Saturating(i16::MIN), &[Token::I32(i32::MIN)]); + test(Saturating(i32::MIN), &[Token::I64(i64::MIN)]); + + test(Saturating(u8::MIN), &[Token::I8(-1)]); + test(Saturating(u16::MIN), &[Token::I16(-1)]); + + #[cfg(target_pointer_width = "64")] + { + test(Saturating(usize::MIN), &[Token::U64(u64::MIN)]); + test(Saturating(usize::MAX), &[Token::U64(u64::MAX)]); + test(Saturating(isize::MIN), &[Token::I64(i64::MIN)]); + test(Saturating(isize::MAX), &[Token::I64(i64::MAX)]); + test(Saturating(0usize), &[Token::I64(i64::MIN)]); + + test( + Saturating(9_223_372_036_854_775_807usize), + &[Token::I64(i64::MAX)], + ); } - test_path { - Path::new("/usr/local/lib") => &[ - Token::BorrowedStr("/usr/local/lib"), - ], - Path::new("/usr/local/lib") => &[ - Token::BorrowedBytes(b"/usr/local/lib"), - ], - } - test_path_buf { - PathBuf::from("/usr/local/lib") => &[ - Token::Str("/usr/local/lib"), - ], - PathBuf::from("/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 { - CString::new("abc").unwrap() => &[ - Token::Bytes(b"abc"), - ], - } - test_rc { - Rc::new(true) => &[ - Token::Bool(true), - ], - } - test_rc_weak_some { - SkipPartialEq(RcWeak::::new()) => &[ - Token::Some, - Token::Bool(true), - ], - } - test_rc_weak_none { - SkipPartialEq(RcWeak::::new()) => &[ - Token::None, - ], - } - test_arc { - Arc::new(true) => &[ - Token::Bool(true), - ], - } - test_arc_weak_some { - SkipPartialEq(ArcWeak::::new()) => &[ - Token::Some, - Token::Bool(true), - ], - } - test_arc_weak_none { - SkipPartialEq(ArcWeak::::new()) => &[ - Token::None, - ], - } - test_wrapping { - Wrapping(1usize) => &[ - Token::U32(1), - ], - Wrapping(1usize) => &[ - Token::U64(1), - ], - } - test_rc_dst { - Rc::::from("s") => &[ - Token::Str("s"), - ], - Rc::<[bool]>::from(&[true][..]) => &[ +} + +#[test] +fn test_rc_dst() { + test(Rc::::from("s"), &[Token::Str("s")]); + test( + Rc::<[bool]>::from(&[true][..]), + &[ Token::Seq { len: Some(1) }, Token::Bool(true), Token::SeqEnd, ], - } - test_arc_dst { - Arc::::from("s") => &[ - Token::Str("s"), - ], - Arc::<[bool]>::from(&[true][..]) => &[ + ); +} + +#[test] +fn test_arc_dst() { + test(Arc::::from("s"), &[Token::Str("s")]); + test( + Arc::<[bool]>::from(&[true][..]), + &[ Token::Seq { len: Some(1) }, Token::Bool(true), Token::SeqEnd, ], - } - test_ignored_any { - IgnoredAny => &[ - Token::Str("s"), - ], - IgnoredAny => &[ + ); +} + +#[test] +fn test_ignored_any() { + test(IgnoredAny, &[Token::Str("s")]); + test( + IgnoredAny, + &[ Token::Seq { len: Some(1) }, Token::Bool(true), Token::SeqEnd, ], - IgnoredAny => &[ - Token::Enum { name: "E" }, - Token::Str("Rust"), - Token::Unit, - ], - } + ); + test( + IgnoredAny, + &[Token::Enum { name: "E" }, Token::Str("Rust"), Token::Unit], + ); +} + +#[test] +fn test_net_ipv4addr_readable() { + test( + "1.2.3.4".parse::().unwrap().readable(), + &[Token::Str("1.2.3.4")], + ); } -declare_tests! { - readable +#[test] +fn test_net_ipv6addr_readable() { + test( + "::1".parse::().unwrap().readable(), + &[Token::Str("::1")], + ); +} - test_net_ipv4addr_readable { - "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], - } - test_net_ipv6addr_readable { - "::1".parse::().unwrap() => &[Token::Str("::1")], - } - test_net_ipaddr_readable { - "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], - } - test_net_socketaddr_readable { - "1.2.3.4:1234".parse::().unwrap() => &[Token::Str("1.2.3.4:1234")], - "1.2.3.4:1234".parse::().unwrap() => &[Token::Str("1.2.3.4:1234")], - "[::1]:1234".parse::().unwrap() => &[Token::Str("[::1]:1234")], - } +#[test] +fn test_net_ipaddr_readable() { + test( + "1.2.3.4".parse::().unwrap().readable(), + &[Token::Str("1.2.3.4")], + ); } -declare_tests! { - compact +#[test] +fn test_net_socketaddr_readable() { + test( + "1.2.3.4:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("1.2.3.4:1234")], + ); + test( + "1.2.3.4:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("1.2.3.4:1234")], + ); + test( + "[::1]:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("[::1]:1234")], + ); +} - test_net_ipv4addr_compact { - net::Ipv4Addr::from(*b"1234") => &seq![ +#[test] +fn test_net_ipv4addr_compact() { + test( + net::Ipv4Addr::from(*b"1234").compact(), + &seq![ Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd ], - } - test_net_ipv6addr_compact { - net::Ipv6Addr::from(*b"1234567890123456") => &seq![ + ); +} + +#[test] +fn test_net_ipv6addr_compact() { + test( + net::Ipv6Addr::from(*b"1234567890123456").compact(), + &seq![ Token::Tuple { len: 4 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd ], - } - test_net_ipaddr_compact { - net::IpAddr::from(*b"1234") => &seq![ - Token::NewtypeVariant { name: "IpAddr", variant: "V4" }, + ); +} +#[test] +fn test_net_ipaddr_compact() { + test( + net::IpAddr::from(*b"1234").compact(), + &seq![ + Token::NewtypeVariant { + name: "IpAddr", + variant: "V4" + }, Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd ], - } - test_net_socketaddr_compact { - net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![ - Token::NewtypeVariant { name: "SocketAddr", variant: "V6" }, + ); +} +#[test] +fn test_net_socketaddr_compact() { + test( + net::SocketAddr::from((*b"1234567890123456", 1234)).compact(), + &seq![ + Token::NewtypeVariant { + name: "SocketAddr", + variant: "V6" + }, Token::Tuple { len: 2 }, - Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd ], - net::SocketAddr::from((*b"1234", 1234)) => &seq![ - Token::NewtypeVariant { name: "SocketAddr", variant: "V4" }, - + ); + test( + net::SocketAddr::from((*b"1234", 1234)).compact(), + &seq![ + Token::NewtypeVariant { + name: "SocketAddr", + variant: "V4" + }, Token::Tuple { len: 2 }, - Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd ], - net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![ + ); + test( + net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234).compact(), + &seq![ Token::Tuple { len: 2 }, - Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd ], - net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![ + ); + test( + net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0).compact(), + &seq![ Token::Tuple { len: 2 }, - Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd ], - } + ); } #[cfg(feature = "unstable")] -declare_tests! { - test_never_result { - Ok::(0) => &[ - Token::NewtypeVariant { name: "Result", variant: "Ok" }, +#[test] +fn test_never_result() { + test( + Ok::(0), + &[ + Token::NewtypeVariant { + name: "Result", + variant: "Ok", + }, Token::U8(0), ], - } + ); } #[cfg(unix)] @@ -1154,302 +2352,36 @@ fn test_cstr() { ); } -#[test] -fn test_cstr_internal_null() { - assert_de_tokens_error::>( - &[Token::Bytes(b"a\0c")], - "nul byte found in provided data at position: 1", - ); -} - -#[test] -fn test_cstr_internal_null_end() { - assert_de_tokens_error::>( - &[Token::Bytes(b"ac\0")], - "nul byte found in provided data at position: 2", - ); -} - -#[cfg(feature = "unstable")] -#[test] -fn test_never_type() { - assert_de_tokens_error::(&[], "cannot deserialize `!`"); - - assert_de_tokens_error::>( - &[Token::NewtypeVariant { - name: "Result", - variant: "Err", - }], - "cannot deserialize `!`", - ); -} - #[test] fn test_atomics() { - fn test(load: L, val: T, token: Token) + fn test(load: L, val: T) where L: Fn(&A, Ordering) -> T, A: DeserializeOwned, - T: PartialEq + Debug, + T: PartialEq + Debug + Copy + for<'de> IntoDeserializer<'de>, { - let tokens = &[token]; - let mut de = serde_test::Deserializer::new(tokens); - match A::deserialize(&mut de) { + match A::deserialize(val.into_deserializer()) { Ok(v) => { - let loaded = load(&v, Ordering::SeqCst); + let loaded = load(&v, Ordering::Relaxed); assert_eq!(val, loaded); } Err(e) => panic!("tokens failed to deserialize: {}", e), - }; - if de.remaining() > 0 { - panic!("{} remaining tokens", de.remaining()); } } - test(AtomicBool::load, true, Token::Bool(true)); - test(AtomicI8::load, -127, Token::I8(-127i8)); - test(AtomicI16::load, -510, Token::I16(-510i16)); - test(AtomicI32::load, -131072, Token::I32(-131072i32)); - test(AtomicIsize::load, -131072isize, Token::I32(-131072)); - test(AtomicU8::load, 127, Token::U8(127u8)); - test(AtomicU16::load, 510u16, Token::U16(510u16)); - test(AtomicU32::load, 131072u32, Token::U32(131072u32)); - test(AtomicUsize::load, 131072usize, Token::U32(131072)); + test(AtomicBool::load, true); + test(AtomicI8::load, -127i8); + test(AtomicI16::load, -510i16); + test(AtomicI32::load, -131072i32); + test(AtomicIsize::load, -131072isize); + test(AtomicU8::load, 127u8); + test(AtomicU16::load, 510u16); + test(AtomicU32::load, 131072u32); + test(AtomicUsize::load, 131072usize); #[cfg(target_arch = "x86_64")] { - test(AtomicI64::load, -8589934592, Token::I64(-8589934592)); - test(AtomicU64::load, 8589934592u64, Token::U64(8589934592)); - } -} - -declare_error_tests! { - test_unknown_field { - &[ - Token::Struct { name: "StructDenyUnknown", len: 1 }, - Token::Str("a"), - Token::I32(0), - - Token::Str("d"), - ], - "unknown field `d`, expected `a`", - } - test_skipped_field_is_unknown { - &[ - Token::Struct { name: "StructDenyUnknown", len: 1 }, - Token::Str("b"), - ], - "unknown field `b`, expected `a`", - } - test_skip_all_deny_unknown { - &[ - Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 }, - Token::Str("a"), - ], - "unknown field `a`, there are no fields", - } - test_unknown_variant { - &[ - Token::UnitVariant { name: "Enum", variant: "Foo" }, - ], - "unknown variant `Foo`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`", - } - test_enum_skipped_variant { - &[ - Token::UnitVariant { name: "Enum", variant: "Skipped" }, - ], - "unknown variant `Skipped`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`", - } - test_enum_skip_all { - &[ - Token::UnitVariant { name: "EnumSkipAll", variant: "Skipped" }, - ], - "unknown variant `Skipped`, there are no variants", - } - test_duplicate_field_struct { - &[ - Token::Map { len: Some(3) }, - Token::Str("a"), - Token::I32(1), - - Token::Str("a"), - ], - "duplicate field `a`", - } - test_duplicate_field_enum { - &[ - Token::StructVariant { name: "Enum", variant: "Map", len: 3 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("a"), - ], - "duplicate field `a`", - } - test_enum_out_of_range { - &[ - Token::Enum { name: "Enum" }, - Token::U32(5), - Token::Unit, - ], - "invalid value: integer `5`, expected variant index 0 <= i < 5", - } - test_short_tuple<(u8, u8, u8)> { - &[ - Token::Tuple { len: 1 }, - Token::U8(1), - Token::TupleEnd, - ], - "invalid length 1, expected a tuple of size 3", - } - test_short_array<[u8; 3]> { - &[ - Token::Seq { len: Some(1) }, - Token::U8(1), - Token::SeqEnd, - ], - "invalid length 1, expected an array of length 3", - } - test_cstring_internal_null { - &[ - Token::Bytes(b"a\0c"), - ], - "nul byte found in provided data at position: 1", - } - test_cstring_internal_null_end { - &[ - Token::Bytes(b"ac\0"), - ], - "nul byte found in provided data at position: 2", - } - test_unit_from_empty_seq<()> { - &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ], - "invalid type: sequence, expected unit", - } - test_unit_from_empty_seq_without_len<()> { - &[ - Token::Seq { len: None }, - Token::SeqEnd, - ], - "invalid type: sequence, expected unit", - } - test_unit_from_tuple_struct<()> { - &[ - Token::TupleStruct { name: "Anything", len: 0 }, - Token::TupleStructEnd, - ], - "invalid type: sequence, expected unit", - } - test_string_from_unit { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a string", - } - test_btreeset_from_unit> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a sequence", - } - test_btreeset_from_unit_struct> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected a sequence", - } - test_hashset_from_unit> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a sequence", - } - test_hashset_from_unit_struct> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected a sequence", - } - test_vec_from_unit> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a sequence", - } - test_vec_from_unit_struct> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected a sequence", - } - test_zero_array_from_unit<[isize; 0]> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected an empty array", - } - test_zero_array_from_unit_struct<[isize; 0]> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected an empty array", - } - test_btreemap_from_unit> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a map", - } - test_btreemap_from_unit_struct> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected a map", - } - test_hashmap_from_unit> { - &[ - Token::Unit, - ], - "invalid type: unit value, expected a map", - } - test_hashmap_from_unit_struct> { - &[ - Token::UnitStruct { name: "Anything" }, - ], - "invalid type: unit value, expected a map", - } - test_bool_from_string { - &[ - Token::Str("false"), - ], - "invalid type: string \"false\", expected a boolean", - } - test_number_from_string { - &[ - Token::Str("1"), - ], - "invalid type: string \"1\", expected isize", - } - test_integer_from_float { - &[ - Token::F32(0.0), - ], - "invalid type: floating point `0`, expected isize", - } - test_unit_struct_from_seq { - &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ], - "invalid type: sequence, expected unit struct UnitStruct", - } - test_wrapping_overflow> { - &[ - Token::U32(65_536), - ], - "invalid value: integer `65536`, expected u16", + test(AtomicI64::load, -8589934592i64); + test(AtomicU64::load, 8589934592u64); } } diff --git a/test_suite/tests/test_de_error.rs b/test_suite/tests/test_de_error.rs new file mode 100644 index 000000000..32a425a71 --- /dev/null +++ b/test_suite/tests/test_de_error.rs @@ -0,0 +1,1568 @@ +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::empty_enums, + clippy::unreadable_literal +)] +#![cfg_attr(feature = "unstable", feature(never_type))] + +use serde::de::{Deserialize, IntoDeserializer}; +use serde_derive::Deserialize; +use serde_test::{assert_de_tokens_error, Token}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::ffi::{CStr, CString}; +use std::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, +}; +use std::time::{Duration, SystemTime}; + +#[derive(Copy, Clone, PartialEq, Debug, Deserialize)] +struct UnitStruct; + +#[derive(PartialEq, Debug, Deserialize)] +struct Struct { + a: i32, + b: i32, + #[serde(skip_deserializing)] + c: i32, +} + +#[derive(PartialEq, Debug, Deserialize)] +#[serde(deny_unknown_fields)] +struct StructDenyUnknown { + a: i32, + #[serde(skip_deserializing)] + b: i32, +} + +#[derive(PartialEq, Debug, Deserialize)] +#[serde(deny_unknown_fields)] +struct StructSkipAllDenyUnknown { + #[serde(skip_deserializing)] + a: i32, +} + +#[derive(Default, PartialEq, Debug)] +struct NotDeserializable; + +#[derive(PartialEq, Debug, Deserialize)] +enum Enum { + #[allow(dead_code)] + #[serde(skip_deserializing)] + Skipped, + Unit, + Simple(i32), + Seq(i32, i32, i32), + Map { + a: i32, + b: i32, + c: i32, + }, + SimpleWithSkipped(#[serde(skip_deserializing)] NotDeserializable), +} + +#[derive(PartialEq, Debug, Deserialize)] +enum EnumSkipAll { + #[allow(dead_code)] + #[serde(skip_deserializing)] + Skipped, +} + +#[test] +fn test_i8() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I16(-129)], + "invalid value: integer `-129`, expected i8", + ); + test( + &[Token::I32(-129)], + "invalid value: integer `-129`, expected i8", + ); + test( + &[Token::I64(-129)], + "invalid value: integer `-129`, expected i8", + ); + test( + &[Token::I16(128)], + "invalid value: integer `128`, expected i8", + ); + test( + &[Token::I32(128)], + "invalid value: integer `128`, expected i8", + ); + test( + &[Token::I64(128)], + "invalid value: integer `128`, expected i8", + ); + + // from unsigned + test( + &[Token::U8(128)], + "invalid value: integer `128`, expected i8", + ); + test( + &[Token::U16(128)], + "invalid value: integer `128`, expected i8", + ); + test( + &[Token::U32(128)], + "invalid value: integer `128`, expected i8", + ); + test( + &[Token::U64(128)], + "invalid value: integer `128`, expected i8", + ); +} + +#[test] +fn test_i16() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I32(-32769)], + "invalid value: integer `-32769`, expected i16", + ); + test( + &[Token::I64(-32769)], + "invalid value: integer `-32769`, expected i16", + ); + test( + &[Token::I32(32768)], + "invalid value: integer `32768`, expected i16", + ); + test( + &[Token::I64(32768)], + "invalid value: integer `32768`, expected i16", + ); + + // from unsigned + test( + &[Token::U16(32768)], + "invalid value: integer `32768`, expected i16", + ); + test( + &[Token::U32(32768)], + "invalid value: integer `32768`, expected i16", + ); + test( + &[Token::U64(32768)], + "invalid value: integer `32768`, expected i16", + ); +} + +#[test] +fn test_i32() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I64(-2147483649)], + "invalid value: integer `-2147483649`, expected i32", + ); + test( + &[Token::I64(2147483648)], + "invalid value: integer `2147483648`, expected i32", + ); + + // from unsigned + test( + &[Token::U32(2147483648)], + "invalid value: integer `2147483648`, expected i32", + ); + test( + &[Token::U64(2147483648)], + "invalid value: integer `2147483648`, expected i32", + ); +} + +#[test] +fn test_i64() { + let test = assert_de_tokens_error::; + + // from unsigned + test( + &[Token::U64(9223372036854775808)], + "invalid value: integer `9223372036854775808`, expected i64", + ); +} + +#[test] +fn test_i128() { + let deserializer = ::into_deserializer(1); + let error = <&str>::deserialize(deserializer).unwrap_err(); + assert_eq!( + error.to_string(), + "invalid type: integer `1` as i128, expected a borrowed string", + ); +} + +#[test] +fn test_u8() { + let test = assert_de_tokens_error::; + + // from signed + test(&[Token::I8(-1)], "invalid value: integer `-1`, expected u8"); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected u8", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected u8", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected u8", + ); + test( + &[Token::I16(256)], + "invalid value: integer `256`, expected u8", + ); + test( + &[Token::I32(256)], + "invalid value: integer `256`, expected u8", + ); + test( + &[Token::I64(256)], + "invalid value: integer `256`, expected u8", + ); + + // from unsigned + test( + &[Token::U16(256)], + "invalid value: integer `256`, expected u8", + ); + test( + &[Token::U32(256)], + "invalid value: integer `256`, expected u8", + ); + test( + &[Token::U64(256)], + "invalid value: integer `256`, expected u8", + ); +} + +#[test] +fn test_u16() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected u16", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected u16", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected u16", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected u16", + ); + test( + &[Token::I32(65536)], + "invalid value: integer `65536`, expected u16", + ); + test( + &[Token::I64(65536)], + "invalid value: integer `65536`, expected u16", + ); + + // from unsigned + test( + &[Token::U32(65536)], + "invalid value: integer `65536`, expected u16", + ); + test( + &[Token::U64(65536)], + "invalid value: integer `65536`, expected u16", + ); +} + +#[test] +fn test_u32() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected u32", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected u32", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected u32", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected u32", + ); + test( + &[Token::I64(4294967296)], + "invalid value: integer `4294967296`, expected u32", + ); + + // from unsigned + test( + &[Token::U64(4294967296)], + "invalid value: integer `4294967296`, expected u32", + ); +} + +#[test] +fn test_u64() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected u64", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected u64", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected u64", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected u64", + ); + + let deserializer = ::into_deserializer(1); + let error = <&str>::deserialize(deserializer).unwrap_err(); + assert_eq!( + error.to_string(), + "invalid type: integer `1`, expected a borrowed string", + ); +} + +#[test] +fn test_u128() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected u128", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected u128", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected u128", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected u128", + ); + + let deserializer = ::into_deserializer(1); + let error = <&str>::deserialize(deserializer).unwrap_err(); + assert_eq!( + error.to_string(), + "invalid type: integer `1` as u128, expected a borrowed string", + ); +} + +#[test] +fn test_usize() { + let test = assert_de_tokens_error::; + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected usize", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected usize", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected usize", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected usize", + ); +} + +#[test] +fn test_nonzero_i8() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero i8", + ); + + // from signed + test( + &[Token::I16(-129)], + "invalid value: integer `-129`, expected a nonzero i8", + ); + test( + &[Token::I32(-129)], + "invalid value: integer `-129`, expected a nonzero i8", + ); + test( + &[Token::I64(-129)], + "invalid value: integer `-129`, expected a nonzero i8", + ); + test( + &[Token::I16(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + test( + &[Token::I32(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + test( + &[Token::I64(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + + // from unsigned + test( + &[Token::U8(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + test( + &[Token::U16(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + test( + &[Token::U32(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); + test( + &[Token::U64(128)], + "invalid value: integer `128`, expected a nonzero i8", + ); +} + +#[test] +fn test_nonzero_i16() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero i16", + ); + + // from signed + test( + &[Token::I32(-32769)], + "invalid value: integer `-32769`, expected a nonzero i16", + ); + test( + &[Token::I64(-32769)], + "invalid value: integer `-32769`, expected a nonzero i16", + ); + test( + &[Token::I32(32768)], + "invalid value: integer `32768`, expected a nonzero i16", + ); + test( + &[Token::I64(32768)], + "invalid value: integer `32768`, expected a nonzero i16", + ); + + // from unsigned + test( + &[Token::U16(32768)], + "invalid value: integer `32768`, expected a nonzero i16", + ); + test( + &[Token::U32(32768)], + "invalid value: integer `32768`, expected a nonzero i16", + ); + test( + &[Token::U64(32768)], + "invalid value: integer `32768`, expected a nonzero i16", + ); +} + +#[test] +fn test_nonzero_i32() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero i32", + ); + + // from signed + test( + &[Token::I64(-2147483649)], + "invalid value: integer `-2147483649`, expected a nonzero i32", + ); + test( + &[Token::I64(2147483648)], + "invalid value: integer `2147483648`, expected a nonzero i32", + ); + + // from unsigned + test( + &[Token::U32(2147483648)], + "invalid value: integer `2147483648`, expected a nonzero i32", + ); + test( + &[Token::U64(2147483648)], + "invalid value: integer `2147483648`, expected a nonzero i32", + ); +} + +#[test] +fn test_nonzero_i64() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero i64", + ); + + // from unsigned + test( + &[Token::U64(9223372036854775808)], + "invalid value: integer `9223372036854775808`, expected a nonzero i64", + ); +} + +#[test] +fn test_nonzero_i128() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero i128", + ); +} + +#[test] +fn test_nonzero_isize() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero isize", + ); +} + +#[test] +fn test_nonzero_u8() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero u8", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero u8", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero u8", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero u8", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero u8", + ); + test( + &[Token::I16(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); + test( + &[Token::I32(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); + test( + &[Token::I64(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); + + // from unsigned + test( + &[Token::U16(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); + test( + &[Token::U32(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); + test( + &[Token::U64(256)], + "invalid value: integer `256`, expected a nonzero u8", + ); +} + +#[test] +fn test_nonzero_u16() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero u16", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero u16", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero u16", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero u16", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero u16", + ); + test( + &[Token::I32(65536)], + "invalid value: integer `65536`, expected a nonzero u16", + ); + test( + &[Token::I64(65536)], + "invalid value: integer `65536`, expected a nonzero u16", + ); + + // from unsigned + test( + &[Token::U32(65536)], + "invalid value: integer `65536`, expected a nonzero u16", + ); + test( + &[Token::U64(65536)], + "invalid value: integer `65536`, expected a nonzero u16", + ); +} + +#[test] +fn test_nonzero_u32() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero u32", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero u32", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero u32", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero u32", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero u32", + ); + test( + &[Token::I64(4294967296)], + "invalid value: integer `4294967296`, expected a nonzero u32", + ); + + // from unsigned + test( + &[Token::U64(4294967296)], + "invalid value: integer `4294967296`, expected a nonzero u32", + ); +} + +#[test] +fn test_nonzero_u64() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero u64", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero u64", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero u64", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero u64", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero u64", + ); +} + +#[test] +fn test_nonzero_u128() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero u128", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero u128", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero u128", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero u128", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero u128", + ); +} + +#[test] +fn test_nonzero_usize() { + let test = assert_de_tokens_error::; + + // from zero + test( + &[Token::I8(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::I16(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::I32(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::I64(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::U8(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::U16(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::U32(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + test( + &[Token::U64(0)], + "invalid value: integer `0`, expected a nonzero usize", + ); + + // from signed + test( + &[Token::I8(-1)], + "invalid value: integer `-1`, expected a nonzero usize", + ); + test( + &[Token::I16(-1)], + "invalid value: integer `-1`, expected a nonzero usize", + ); + test( + &[Token::I32(-1)], + "invalid value: integer `-1`, expected a nonzero usize", + ); + test( + &[Token::I64(-1)], + "invalid value: integer `-1`, expected a nonzero usize", + ); +} + +#[test] +fn test_unknown_field() { + assert_de_tokens_error::( + &[ + Token::Struct { + name: "StructDenyUnknown", + len: 1, + }, + Token::Str("a"), + Token::I32(0), + Token::Str("d"), + ], + "unknown field `d`, expected `a`", + ); +} + +#[test] +fn test_skipped_field_is_unknown() { + assert_de_tokens_error::( + &[ + Token::Struct { + name: "StructDenyUnknown", + len: 1, + }, + Token::Str("b"), + ], + "unknown field `b`, expected `a`", + ); +} + +#[test] +fn test_skip_all_deny_unknown() { + assert_de_tokens_error::( + &[ + Token::Struct { + name: "StructSkipAllDenyUnknown", + len: 0, + }, + Token::Str("a"), + ], + "unknown field `a`, there are no fields", + ); +} + +#[test] +fn test_unknown_variant() { + assert_de_tokens_error::( + &[ + Token::UnitVariant { name: "Enum", variant: "Foo" }, + ], + "unknown variant `Foo`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`", + ); +} + +#[test] +fn test_enum_skipped_variant() { + assert_de_tokens_error::( + &[ + Token::UnitVariant { name: "Enum", variant: "Skipped" }, + ], + "unknown variant `Skipped`, expected one of `Unit`, `Simple`, `Seq`, `Map`, `SimpleWithSkipped`", + ); +} + +#[test] +fn test_enum_skip_all() { + assert_de_tokens_error::( + &[Token::UnitVariant { + name: "EnumSkipAll", + variant: "Skipped", + }], + "unknown variant `Skipped`, there are no variants", + ); +} + +#[test] +fn test_duplicate_field_struct() { + assert_de_tokens_error::( + &[ + Token::Map { len: Some(3) }, + Token::Str("a"), + Token::I32(1), + Token::Str("a"), + ], + "duplicate field `a`", + ); +} + +#[test] +fn test_duplicate_field_enum() { + assert_de_tokens_error::( + &[ + Token::StructVariant { + name: "Enum", + variant: "Map", + len: 3, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("a"), + ], + "duplicate field `a`", + ); +} + +#[test] +fn test_enum_out_of_range() { + assert_de_tokens_error::( + &[Token::Enum { name: "Enum" }, Token::U32(5), Token::Unit], + "invalid value: integer `5`, expected variant index 0 <= i < 5", + ); +} + +#[test] +fn test_short_tuple() { + assert_de_tokens_error::<(u8, u8, u8)>( + &[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd], + "invalid length 1, expected a tuple of size 3", + ); +} + +#[test] +fn test_short_array() { + assert_de_tokens_error::<[u8; 3]>( + &[Token::Seq { len: Some(1) }, Token::U8(1), Token::SeqEnd], + "invalid length 1, expected an array of length 3", + ); +} + +#[test] +fn test_cstring_internal_null() { + assert_de_tokens_error::( + &[Token::Bytes(b"a\0c")], + "nul byte found in provided data at position: 1", + ); +} + +#[test] +fn test_cstring_internal_null_end() { + assert_de_tokens_error::( + &[Token::Bytes(b"ac\0")], + "nul byte found in provided data at position: 2", + ); +} + +#[test] +fn test_unit_from_empty_seq() { + assert_de_tokens_error::<()>( + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + "invalid type: sequence, expected unit", + ); +} + +#[test] +fn test_unit_from_empty_seq_without_len() { + assert_de_tokens_error::<()>( + &[Token::Seq { len: None }, Token::SeqEnd], + "invalid type: sequence, expected unit", + ); +} + +#[test] +fn test_unit_from_tuple_struct() { + assert_de_tokens_error::<()>( + &[ + Token::TupleStruct { + name: "Anything", + len: 0, + }, + Token::TupleStructEnd, + ], + "invalid type: sequence, expected unit", + ); +} + +#[test] +fn test_string_from_unit() { + assert_de_tokens_error::( + &[Token::Unit], + "invalid type: unit value, expected a string", + ); +} + +#[test] +fn test_btreeset_from_unit() { + assert_de_tokens_error::>( + &[Token::Unit], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_btreeset_from_unit_struct() { + assert_de_tokens_error::>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_hashset_from_unit() { + assert_de_tokens_error::>( + &[Token::Unit], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_hashset_from_unit_struct() { + assert_de_tokens_error::>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_vec_from_unit() { + assert_de_tokens_error::>( + &[Token::Unit], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_vec_from_unit_struct() { + assert_de_tokens_error::>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected a sequence", + ); +} + +#[test] +fn test_zero_array_from_unit() { + assert_de_tokens_error::<[isize; 0]>( + &[Token::Unit], + "invalid type: unit value, expected an empty array", + ); +} + +#[test] +fn test_zero_array_from_unit_struct() { + assert_de_tokens_error::<[isize; 0]>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected an empty array", + ); +} + +#[test] +fn test_btreemap_from_unit() { + assert_de_tokens_error::>( + &[Token::Unit], + "invalid type: unit value, expected a map", + ); +} + +#[test] +fn test_btreemap_from_unit_struct() { + assert_de_tokens_error::>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected a map", + ); +} + +#[test] +fn test_hashmap_from_unit() { + assert_de_tokens_error::>( + &[Token::Unit], + "invalid type: unit value, expected a map", + ); +} + +#[test] +fn test_hashmap_from_unit_struct() { + assert_de_tokens_error::>( + &[Token::UnitStruct { name: "Anything" }], + "invalid type: unit value, expected a map", + ); +} + +#[test] +fn test_bool_from_string() { + assert_de_tokens_error::( + &[Token::Str("false")], + "invalid type: string \"false\", expected a boolean", + ); +} + +#[test] +fn test_number_from_string() { + assert_de_tokens_error::( + &[Token::Str("1")], + "invalid type: string \"1\", expected isize", + ); +} + +#[test] +fn test_integer_from_float() { + assert_de_tokens_error::( + &[Token::F32(0.0)], + "invalid type: floating point `0.0`, expected isize", + ); +} + +#[test] +fn test_nan_no_decimal_point() { + assert_de_tokens_error::( + &[Token::F32(f32::NAN)], + "invalid type: floating point `NaN`, expected isize", + ); +} + +#[test] +fn test_unit_struct_from_seq() { + assert_de_tokens_error::( + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + "invalid type: sequence, expected unit struct UnitStruct", + ); +} + +#[test] +fn test_wrapping_overflow() { + assert_de_tokens_error::>( + &[Token::U32(65_536)], + "invalid value: integer `65536`, expected u16", + ); +} + +#[test] +fn test_duration_overflow_seq() { + assert_de_tokens_error::( + &[ + Token::Seq { len: Some(2) }, + Token::U64(u64::MAX), + Token::U32(1_000_000_000), + Token::SeqEnd, + ], + "overflow deserializing Duration", + ); +} + +#[test] +fn test_duration_overflow_struct() { + assert_de_tokens_error::( + &[ + Token::Struct { + name: "Duration", + len: 2, + }, + Token::Str("secs"), + Token::U64(u64::MAX), + Token::Str("nanos"), + Token::U32(1_000_000_000), + Token::StructEnd, + ], + "overflow deserializing Duration", + ); +} + +#[test] +fn test_systemtime_overflow_seq() { + assert_de_tokens_error::( + &[ + Token::Seq { len: Some(2) }, + Token::U64(u64::MAX), + Token::U32(1_000_000_000), + Token::SeqEnd, + ], + "overflow deserializing SystemTime epoch offset", + ); +} + +#[test] +fn test_systemtime_overflow_struct() { + assert_de_tokens_error::( + &[ + Token::Struct { + name: "SystemTime", + len: 2, + }, + Token::Str("secs_since_epoch"), + Token::U64(u64::MAX), + Token::Str("nanos_since_epoch"), + Token::U32(1_000_000_000), + Token::StructEnd, + ], + "overflow deserializing SystemTime epoch offset", + ); +} + +#[test] +fn test_systemtime_overflow() { + assert_de_tokens_error::( + &[ + Token::Seq { len: Some(2) }, + Token::U64(u64::MAX), + Token::U32(0), + Token::SeqEnd, + ], + "overflow deserializing SystemTime", + ); +} + +#[test] +fn test_cstr_internal_null() { + assert_de_tokens_error::>( + &[Token::Bytes(b"a\0c")], + "nul byte found in provided data at position: 1", + ); +} + +#[test] +fn test_cstr_internal_null_end() { + assert_de_tokens_error::>( + &[Token::Bytes(b"ac\0")], + "nul byte found in provided data at position: 2", + ); +} + +#[cfg(feature = "unstable")] +#[test] +fn test_never_type() { + assert_de_tokens_error::(&[], "cannot deserialize `!`"); + + assert_de_tokens_error::>( + &[Token::NewtypeVariant { + name: "Result", + variant: "Err", + }], + "cannot deserialize `!`", + ); +} diff --git a/test_suite/tests/test_deprecated.rs b/test_suite/tests/test_deprecated.rs new file mode 100644 index 000000000..0ddf641a6 --- /dev/null +++ b/test_suite/tests/test_deprecated.rs @@ -0,0 +1,30 @@ +#![deny(deprecated)] +#![allow(dead_code)] + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +#[deprecated] +enum DeprecatedEnum { + A, + B, +} + +#[derive(Serialize, Deserialize)] +#[deprecated] +struct DeprecatedStruct { + a: bool, +} + +#[derive(Serialize, Deserialize)] +enum DeprecatedVariant { + A, + #[deprecated] + B, +} + +#[derive(Serialize, Deserialize)] +struct DeprecatedField { + #[deprecated] + a: bool, +} diff --git a/test_suite/tests/test_enum_adjacently_tagged.rs b/test_suite/tests/test_enum_adjacently_tagged.rs new file mode 100644 index 000000000..0bcdbc39e --- /dev/null +++ b/test_suite/tests/test_enum_adjacently_tagged.rs @@ -0,0 +1,799 @@ +#![deny(trivial_numeric_casts)] +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::enum_variant_names, + clippy::redundant_field_names, + clippy::too_many_lines +)] + +use serde_derive::{Deserialize, Serialize}; +use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag = "t", content = "c")] +enum AdjacentlyTagged { + Unit, + Newtype(T), + Tuple(u8, u8), + Struct { f: u8 }, +} + +mod unit { + use super::*; + + #[test] + fn map_str_tag_only() { + // Map: tag only + assert_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + + // Map: tag only and incorrect hint for number of elements + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_int_tag_only() { + // Map: tag (as number) only + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::U16(0), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_bytes_tag_only() { + // Map: tag only + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::Bytes(b"t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + + // Map: tag only + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::BorrowedBytes(b"t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_str_tag_content() { + // Map: tag + content + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::Str("c"), + Token::Unit, + Token::StructEnd, + ], + ); + // Map: content + tag + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Unit, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + + // Map: tag + content + excess fields (f, g, h) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("f"), + Token::Unit, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::Str("g"), + Token::Unit, + Token::Str("c"), + Token::Unit, + Token::Str("h"), + Token::Unit, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_int_tag_content() { + // Map: tag (as number) + content (as number) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U8(0), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::U8(1), + Token::Unit, + Token::StructEnd, + ], + ); + + // Map: content (as number) + tag (as number) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(1), + Token::Unit, + Token::U64(0), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_bytes_tag_content() { + // Map: tag + content + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::BorrowedBytes(b"t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::BorrowedBytes(b"c"), + Token::Unit, + Token::StructEnd, + ], + ); + + // Map: content + tag + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Unit, + Token::Bytes(b"t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn seq_tag_content() { + // Seq: tag and content + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Seq { len: Some(2) }, + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::Unit, + Token::SeqEnd, + ], + ); + + // Seq: tag (as string) and content + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Seq { len: None }, + Token::Str("Unit"), // tag + Token::Unit, // content + Token::SeqEnd, + ], + ); + + // Seq: tag (as borrowed string) and content + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Seq { len: None }, + Token::BorrowedStr("Unit"), // tag + Token::Unit, // content + Token::SeqEnd, + ], + ); + } +} + +mod newtype { + use super::*; + + #[test] + fn map_tag_only() { + // optional newtype with no content field + assert_de_tokens( + &AdjacentlyTagged::Newtype::>(None), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Newtype", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn map_tag_content() { + let value = AdjacentlyTagged::Newtype::(1); + + // Map: tag + content + assert_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Newtype", + }, + Token::Str("c"), + Token::U8(1), + Token::StructEnd, + ], + ); + + // Map: content + tag + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::U8(1), + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Newtype", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn seq() { + let value = AdjacentlyTagged::Newtype::(1); + + // Seq: tag and content + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Newtype", + }, + Token::U8(1), + Token::SeqEnd, + ], + ); + + // Seq: tag (as string) and content + assert_de_tokens( + &value, + &[ + Token::Seq { len: None }, + Token::Str("Newtype"), // tag + Token::U8(1), // content + Token::SeqEnd, + ], + ); + + // Seq: tag (as borrowed string) and content + assert_de_tokens( + &value, + &[ + Token::Seq { len: None }, + Token::BorrowedStr("Newtype"), // tag + Token::U8(1), // content + Token::SeqEnd, + ], + ); + } +} + +#[test] +fn newtype_with_newtype() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeStruct(u32); + + assert_de_tokens( + &AdjacentlyTagged::Newtype(NewtypeStruct(5)), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::NewtypeStruct { + name: "NewtypeStruct", + }, + Token::U32(5), + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Newtype", + }, + Token::StructEnd, + ], + ); +} + +mod tuple { + use super::*; + + #[test] + fn map() { + let value = AdjacentlyTagged::Tuple::(1, 1); + + // Map: tag + content + assert_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Tuple", + }, + Token::Str("c"), + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::StructEnd, + ], + ); + + // Map: content + tag + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Tuple", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn seq() { + let value = AdjacentlyTagged::Tuple::(1, 1); + + // Seq: tag + content + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Tuple", + }, + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::SeqEnd, + ], + ); + } +} + +mod struct_ { + use super::*; + + #[test] + fn map() { + let value = AdjacentlyTagged::Struct:: { f: 1 }; + + // Map: tag + content + assert_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Struct", + }, + Token::Str("c"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::StructEnd, + ], + ); + + // Map: content + tag + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Struct", + }, + Token::StructEnd, + ], + ); + } + + #[test] + fn seq() { + let value = AdjacentlyTagged::Struct:: { f: 1 }; + + // Seq: tag + content + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Struct", + }, + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::SeqEnd, + ], + ); + } +} + +#[test] +fn struct_with_flatten() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(tag = "t", content = "c")] + enum Data { + A { + a: i32, + #[serde(flatten)] + flat: Flat, + }, + } + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Flat { + b: i32, + } + + let data = Data::A { + a: 0, + flat: Flat { b: 0 }, + }; + + assert_tokens( + &data, + &[ + Token::Struct { + name: "Data", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "Data", + variant: "A", + }, + Token::Str("c"), + Token::Map { len: None }, + Token::Str("a"), + Token::I32(0), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + Token::StructEnd, + ], + ); +} + +#[test] +fn expecting_message() { + #[derive(Deserialize)] + #[serde(tag = "tag", content = "content")] + #[serde(expecting = "something strange...")] + enum Enum { + AdjacentlyTagged, + } + + assert_de_tokens_error::( + &[Token::Str("AdjacentlyTagged")], + r#"invalid type: string "AdjacentlyTagged", expected something strange..."#, + ); + + assert_de_tokens_error::( + &[Token::Map { len: None }, Token::Unit], + r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#, + ); + + // Check that #[serde(expecting = "...")] doesn't affect variant identifier error message + assert_de_tokens_error::( + &[Token::Map { len: None }, Token::Str("tag"), Token::Unit], + "invalid type: unit value, expected variant of enum Enum", + ); +} + +#[test] +fn partially_untagged() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(tag = "t", content = "c")] + enum Data { + A(u32), + B, + #[serde(untagged)] + Var(u32), + } + + let data = Data::A(7); + + assert_de_tokens( + &data, + &[ + Token::Map { len: None }, + Token::Str("t"), + Token::Str("A"), + Token::Str("c"), + Token::U32(7), + Token::MapEnd, + ], + ); + + let data = Data::Var(42); + + assert_de_tokens(&data, &[Token::U32(42)]); + + // TODO test error output +} + +#[test] +fn deny_unknown_fields() { + #[derive(Debug, PartialEq, Deserialize)] + #[serde(tag = "t", content = "c", deny_unknown_fields)] + enum AdjacentlyTagged { + Unit, + } + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::Str("c"), + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::Str("c"), + Token::Unit, + Token::Str("h"), + ], + r#"invalid value: string "h", expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("h"), + ], + r#"invalid value: string "h", expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Unit, + Token::Str("h"), + ], + r#"invalid value: string "h", expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::UnitVariant { + name: "AdjacentlyTagged", + variant: "Unit", + }, + Token::U64(3), + ], + r#"invalid value: integer `3`, expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Unit, + Token::Bytes(b"h"), + ], + r#"invalid value: byte array, expected "t" or "c""#, + ); +} diff --git a/test_suite/tests/test_enum_internally_tagged.rs b/test_suite/tests/test_enum_internally_tagged.rs new file mode 100644 index 000000000..b4d428c4d --- /dev/null +++ b/test_suite/tests/test_enum_internally_tagged.rs @@ -0,0 +1,1478 @@ +#![deny(trivial_numeric_casts)] +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::enum_variant_names, + clippy::redundant_field_names, + clippy::too_many_lines +)] + +mod bytes; + +use serde_derive::{Deserialize, Serialize}; +use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; +use std::collections::BTreeMap; +use std::iter::FromIterator; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Unit; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Newtype(BTreeMap); + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Struct { + f: u8, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +enum Enum { + Unit, + Newtype(u8), + Tuple(u8, u8), + Struct { f: u8 }, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag = "tag")] +enum InternallyTagged { + Unit, + NewtypeUnit(()), + NewtypeUnitStruct(Unit), + NewtypeNewtype(Newtype), + NewtypeMap(BTreeMap), + NewtypeStruct(Struct), + NewtypeEnum(Enum), + Struct { a: u8 }, + StructEnum { enum_: Enum }, +} + +#[test] +fn unit() { + assert_tokens( + &InternallyTagged::Unit, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::Str("tag"), + Token::Str("Unit"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &InternallyTagged::Unit, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("Unit"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Unit, + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("Unit"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &InternallyTagged::Unit, + &[ + Token::Map { len: Some(1) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("Unit"), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Unit, + &[ + Token::Seq { len: Some(1) }, + Token::Str("Unit"), // tag + Token::SeqEnd, + ], + ); + assert_de_tokens( + &InternallyTagged::Unit, + &[ + Token::Seq { len: Some(1) }, + Token::BorrowedStr("Unit"), // tag + Token::SeqEnd, + ], + ); +} + +#[test] +fn newtype_unit() { + let value = InternallyTagged::NewtypeUnit(()); + + assert_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("NewtypeUnit"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeUnit"), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::Str("tag"), + Token::Str("NewtypeUnit"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeUnit"), + Token::StructEnd, + ], + ); +} + +#[test] +fn newtype_unit_struct() { + let value = InternallyTagged::NewtypeUnitStruct(Unit); + + assert_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("NewtypeUnitStruct"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeUnitStruct"), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::Str("tag"), + Token::Str("NewtypeUnitStruct"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 1, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeUnitStruct"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(1) }, + Token::Str("NewtypeUnitStruct"), // tag + Token::SeqEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(1) }, + Token::BorrowedStr("NewtypeUnitStruct"), // tag + Token::SeqEnd, + ], + ); +} + +#[test] +fn newtype_newtype() { + assert_tokens( + &InternallyTagged::NewtypeNewtype(Newtype(BTreeMap::new())), + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("NewtypeNewtype"), + Token::MapEnd, + ], + ); +} + +#[test] +fn newtype_map() { + let value = InternallyTagged::NewtypeMap(BTreeMap::new()); + + // Special case: empty map + assert_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("NewtypeMap"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(1) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeMap"), + Token::MapEnd, + ], + ); + + let value = InternallyTagged::NewtypeMap(BTreeMap::from_iter([( + "field".to_string(), + "value".to_string(), + )])); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeMap"), + Token::Str("field"), + Token::Str("value"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeMap"), + Token::BorrowedStr("field"), + Token::BorrowedStr("value"), + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("field"), + Token::Str("value"), + Token::Str("tag"), + Token::Str("NewtypeMap"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("field"), + Token::BorrowedStr("value"), + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeMap"), + Token::MapEnd, + ], + ); + + assert_de_tokens_error::( + &[ + Token::Seq { len: Some(2) }, + Token::Str("NewtypeMap"), // tag + Token::Map { len: Some(0) }, + Token::MapEnd, + Token::SeqEnd, + ], + "invalid type: sequence, expected a map", + ); +} + +#[test] +fn newtype_struct() { + let value = InternallyTagged::NewtypeStruct(Struct { f: 6 }); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::Str("tag"), + Token::Str("NewtypeStruct"), + Token::Str("f"), + Token::U8(6), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeStruct"), + Token::BorrowedStr("f"), + Token::U8(6), + Token::StructEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::Str("f"), + Token::U8(6), + Token::Str("tag"), + Token::Str("NewtypeStruct"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "Struct", + len: 2, + }, + Token::BorrowedStr("f"), + Token::U8(6), + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeStruct"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::Str("NewtypeStruct"), // tag + Token::U8(6), + Token::SeqEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::BorrowedStr("NewtypeStruct"), // tag + Token::U8(6), + Token::SeqEnd, + ], + ); +} + +mod newtype_enum { + use super::*; + + #[test] + fn unit() { + let value = InternallyTagged::NewtypeEnum(Enum::Unit); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::Str("Unit"), + Token::Unit, + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::BorrowedStr("Unit"), + Token::Unit, + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("Unit"), + Token::Unit, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("Unit"), + Token::Unit, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::MapEnd, + ], + ); + } + + #[test] + fn newtype() { + let value = InternallyTagged::NewtypeEnum(Enum::Newtype(1)); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::Str("Newtype"), + Token::U8(1), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::BorrowedStr("Newtype"), + Token::U8(1), + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("Newtype"), + Token::U8(1), + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("Newtype"), + Token::U8(1), + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::MapEnd, + ], + ); + } + + #[test] + fn tuple() { + let value = InternallyTagged::NewtypeEnum(Enum::Tuple(1, 1)); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::Str("Tuple"), + Token::TupleStruct { + name: "Tuple", + len: 2, + }, + Token::U8(1), + Token::U8(1), + Token::TupleStructEnd, + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::BorrowedStr("Tuple"), + Token::TupleStruct { + name: "Tuple", + len: 2, + }, + Token::U8(1), + Token::U8(1), + Token::TupleStructEnd, + Token::MapEnd, + ], + ); + + // Special case: tag field ("tag") is not the first field + // Reaches crate::private::de::content::VariantDeserializer::tuple_variant + // Content::Seq case + // via ContentDeserializer::deserialize_enum + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("Tuple"), + Token::TupleStruct { + name: "Tuple", + len: 2, + }, + Token::U8(1), + Token::U8(1), + Token::TupleStructEnd, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("Tuple"), + Token::TupleStruct { + name: "Tuple", + len: 2, + }, + Token::U8(1), + Token::U8(1), + Token::TupleStructEnd, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::MapEnd, + ], + ); + } + + #[test] + fn struct_() { + let value = InternallyTagged::NewtypeEnum(Enum::Struct { f: 1 }); + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::Str("Struct"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::BorrowedStr("Struct"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::BorrowedStr("f"), + Token::U8(1), + Token::StructEnd, + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Map case + // via ContentDeserializer::deserialize_enum + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("Struct"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("Struct"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::BorrowedStr("f"), + Token::U8(1), + Token::StructEnd, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::MapEnd, + ], + ); + + // Special case: tag field ("tag") is the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::Str("Struct"), + Token::Seq { len: Some(1) }, + Token::U8(1), // f + Token::SeqEnd, + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::BorrowedStr("Struct"), + Token::Seq { len: Some(1) }, + Token::U8(1), // f + Token::SeqEnd, + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Seq case + // via ContentDeserializer::deserialize_enum + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("Struct"), + Token::Seq { len: Some(1) }, + Token::U8(1), // f + Token::SeqEnd, + Token::Str("tag"), + Token::Str("NewtypeEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("Struct"), + Token::Seq { len: Some(1) }, + Token::U8(1), // f + Token::SeqEnd, + Token::BorrowedStr("tag"), + Token::BorrowedStr("NewtypeEnum"), + Token::MapEnd, + ], + ); + } +} + +#[test] +fn struct_() { + let value = InternallyTagged::Struct { a: 1 }; + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("tag"), + Token::Str("Struct"), + Token::Str("a"), + Token::U8(1), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("Struct"), + Token::BorrowedStr("a"), + Token::U8(1), + Token::StructEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("a"), + Token::U8(1), + Token::Str("tag"), + Token::Str("Struct"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::BorrowedStr("a"), + Token::U8(1), + Token::BorrowedStr("tag"), + Token::BorrowedStr("Struct"), + Token::StructEnd, + ], + ); + + // Special case: tag field ("tag") is the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("Struct"), + Token::Str("a"), + Token::U8(1), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("Struct"), + Token::BorrowedStr("a"), + Token::U8(1), + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("a"), + Token::U8(1), + Token::Str("tag"), + Token::Str("Struct"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("a"), + Token::U8(1), + Token::BorrowedStr("tag"), + Token::BorrowedStr("Struct"), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::Str("Struct"), // tag + Token::U8(1), + Token::SeqEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::BorrowedStr("Struct"), // tag + Token::U8(1), + Token::SeqEnd, + ], + ); +} + +mod struct_enum { + use super::*; + + #[test] + fn unit() { + assert_de_tokens( + &Enum::Unit, + &[ + Token::Enum { name: "Enum" }, + Token::BorrowedStr("Unit"), + Token::Unit, + ], + ); + + let value = InternallyTagged::StructEnum { enum_: Enum::Unit }; + + // Special case: tag field ("tag") is the first field + assert_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("tag"), + Token::Str("StructEnum"), + Token::Str("enum_"), + Token::Enum { name: "Enum" }, + Token::Str("Unit"), + Token::Unit, + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("StructEnum"), + Token::BorrowedStr("enum_"), + Token::Enum { name: "Enum" }, + Token::BorrowedStr("Unit"), + Token::Unit, + Token::StructEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("enum_"), + Token::Enum { name: "Enum" }, + Token::Str("Unit"), + Token::Unit, + Token::Str("tag"), + Token::Str("StructEnum"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::BorrowedStr("enum_"), + Token::Enum { name: "Enum" }, + Token::BorrowedStr("Unit"), + Token::Unit, + Token::BorrowedStr("tag"), + Token::BorrowedStr("StructEnum"), + Token::StructEnd, + ], + ); + + // Special case: tag field ("tag") is the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("StructEnum"), + Token::Str("enum_"), + Token::Enum { name: "Enum" }, + Token::Str("Unit"), + Token::Unit, + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("StructEnum"), + Token::BorrowedStr("enum_"), + Token::Enum { name: "Enum" }, + Token::BorrowedStr("Unit"), + Token::Unit, + Token::MapEnd, + ], + ); + + // General case: tag field ("tag") is not the first field + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::Str("enum_"), + Token::Enum { name: "Enum" }, + Token::Str("Unit"), + Token::Unit, + Token::Str("tag"), + Token::Str("StructEnum"), + Token::MapEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Map { len: Some(2) }, + Token::BorrowedStr("enum_"), + Token::Enum { name: "Enum" }, + Token::BorrowedStr("Unit"), + Token::Unit, + Token::BorrowedStr("tag"), + Token::BorrowedStr("StructEnum"), + Token::MapEnd, + ], + ); + + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::Str("StructEnum"), // tag + Token::Enum { name: "Enum" }, // enum_ + Token::Str("Unit"), + Token::Unit, + Token::SeqEnd, + ], + ); + assert_de_tokens( + &value, + &[ + Token::Seq { len: Some(2) }, + Token::BorrowedStr("StructEnum"), // tag + Token::Enum { name: "Enum" }, // enum_ + Token::BorrowedStr("Unit"), + Token::Unit, + Token::SeqEnd, + ], + ); + } +} + +#[test] +fn wrong_tag() { + assert_de_tokens_error::( + &[Token::Map { len: Some(0) }, Token::MapEnd], + "missing field `tag`", + ); + + assert_de_tokens_error::( + &[ + Token::Map { len: Some(1) }, + Token::Str("tag"), + Token::Str("Z"), + Token::MapEnd, + ], + "unknown variant `Z`, expected one of \ + `Unit`, \ + `NewtypeUnit`, \ + `NewtypeUnitStruct`, \ + `NewtypeNewtype`, \ + `NewtypeMap`, \ + `NewtypeStruct`, \ + `NewtypeEnum`, \ + `Struct`, \ + `StructEnum`", + ); +} + +#[test] +fn untagged_variant() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag")] + enum InternallyTagged { + Tagged { + a: u8, + }, + #[serde(untagged)] + Untagged { + tag: String, + b: u8, + }, + } + + assert_de_tokens( + &InternallyTagged::Tagged { a: 1 }, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("Tagged"), + Token::Str("a"), + Token::U8(1), + Token::MapEnd, + ], + ); + + assert_tokens( + &InternallyTagged::Tagged { a: 1 }, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("tag"), + Token::Str("Tagged"), + Token::Str("a"), + Token::U8(1), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Untagged { + tag: "Foo".to_owned(), + b: 2, + }, + &[ + Token::Map { len: Some(2) }, + Token::Str("tag"), + Token::Str("Foo"), + Token::Str("b"), + Token::U8(2), + Token::MapEnd, + ], + ); + + assert_tokens( + &InternallyTagged::Untagged { + tag: "Foo".to_owned(), + b: 2, + }, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("tag"), + Token::Str("Foo"), + Token::Str("b"), + Token::U8(2), + Token::StructEnd, + ], + ); + + assert_tokens( + &InternallyTagged::Untagged { + tag: "Tagged".to_owned(), + b: 2, + }, + &[ + Token::Struct { + name: "InternallyTagged", + len: 2, + }, + Token::Str("tag"), + Token::Str("Tagged"), + Token::Str("b"), + Token::U8(2), + Token::StructEnd, + ], + ); +} + +mod string_and_bytes { + use super::*; + + #[derive(Debug, PartialEq, Deserialize)] + #[serde(tag = "tag")] + enum InternallyTagged { + String { + string: String, + }, + Bytes { + #[serde(with = "bytes")] + bytes: Vec, + }, + } + + #[test] + fn string_from_string() { + assert_de_tokens( + &InternallyTagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("tag"), + Token::Str("String"), + Token::Str("string"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("tag"), + Token::Str("String"), + Token::Str("string"), + Token::String("\0"), + Token::StructEnd, + ], + ); + } + + #[test] + fn string_from_bytes() { + assert_de_tokens( + &InternallyTagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("tag"), + Token::Str("String"), + Token::Str("string"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("tag"), + Token::Str("String"), + Token::Str("string"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + } + + #[test] + fn bytes_from_string() { + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("tag"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("tag"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::String("\0"), + Token::StructEnd, + ], + ); + } + + #[test] + fn bytes_from_bytes() { + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("tag"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("tag"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + } + + #[test] + fn bytes_from_seq() { + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("tag"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Seq { len: Some(1) }, + Token::U8(0), + Token::SeqEnd, + Token::StructEnd, + ], + ); + } +} + +#[test] +fn borrow() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag")] + enum Input<'a> { + Package { name: &'a str }, + } + + assert_tokens( + &Input::Package { name: "borrowed" }, + &[ + Token::Struct { + name: "Input", + len: 2, + }, + Token::BorrowedStr("tag"), + Token::BorrowedStr("Package"), + Token::BorrowedStr("name"), + Token::BorrowedStr("borrowed"), + Token::StructEnd, + ], + ); +} + +#[test] +fn with_skipped_conflict() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag")] + enum Data { + A, + #[serde(skip)] + #[allow(dead_code)] + B { + t: String, + }, + C { + #[serde(default, skip)] + t: String, + }, + } + + let data = Data::C { t: String::new() }; + + assert_tokens( + &data, + &[ + Token::Struct { + name: "Data", + len: 1, + }, + Token::Str("tag"), + Token::Str("C"), + Token::StructEnd, + ], + ); +} + +#[test] +fn containing_flatten() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag")] + enum Data { + A { + a: i32, + #[serde(flatten)] + flat: Flat, + }, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flat { + b: i32, + } + + let data = Data::A { + a: 0, + flat: Flat { b: 0 }, + }; + + assert_tokens( + &data, + &[ + Token::Map { len: None }, + Token::Str("tag"), + Token::Str("A"), + Token::Str("a"), + Token::I32(0), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + ], + ); +} + +#[test] +fn unit_variant_with_unknown_fields() { + let value = InternallyTagged::Unit; + + assert_de_tokens( + &value, + &[ + Token::Map { len: None }, + Token::Str("tag"), + Token::Str("Unit"), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + ], + ); + + // Unknown elements are not allowed in sequences + assert_de_tokens_error::( + &[ + Token::Seq { len: None }, + Token::Str("Unit"), // tag + Token::I32(0), + Token::SeqEnd, + ], + "invalid length 1, expected 0 elements in sequence", + ); +} + +#[test] +fn expecting_message() { + #[derive(Deserialize)] + #[serde(tag = "tag")] + #[serde(expecting = "something strange...")] + enum Enum { + InternallyTagged, + } + + assert_de_tokens_error::( + &[Token::Str("InternallyTagged")], + r#"invalid type: string "InternallyTagged", expected something strange..."#, + ); + + // Check that #[serde(expecting = "...")] doesn't affect variant identifier error message + assert_de_tokens_error::( + &[Token::Map { len: None }, Token::Str("tag"), Token::Unit], + "invalid type: unit value, expected variant identifier", + ); +} diff --git a/test_suite/tests/test_enum_untagged.rs b/test_suite/tests/test_enum_untagged.rs new file mode 100644 index 000000000..48f50c9c2 --- /dev/null +++ b/test_suite/tests/test_enum_untagged.rs @@ -0,0 +1,583 @@ +#![deny(trivial_numeric_casts)] +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::enum_variant_names, + clippy::redundant_field_names, + clippy::too_many_lines +)] + +mod bytes; + +use serde_derive::{Deserialize, Serialize}; +use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; +use std::collections::BTreeMap; + +#[test] +fn complex() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Untagged { + A { a: u8 }, + B { b: u8 }, + C, + D(u8), + E(String), + F(u8, u8), + } + + assert_tokens( + &Untagged::A { a: 1 }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("a"), + Token::U8(1), + Token::StructEnd, + ], + ); + + assert_tokens( + &Untagged::B { b: 2 }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("b"), + Token::U8(2), + Token::StructEnd, + ], + ); + + // Serializes to unit, deserializes from either depending on format's + // preference. + assert_tokens(&Untagged::C, &[Token::Unit]); + assert_de_tokens(&Untagged::C, &[Token::None]); + + assert_tokens(&Untagged::D(4), &[Token::U8(4)]); + assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]); + + assert_tokens( + &Untagged::F(1, 2), + &[ + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(2), + Token::TupleEnd, + ], + ); + + assert_de_tokens_error::( + &[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd], + "data did not match any variant of untagged enum Untagged", + ); + + assert_de_tokens_error::( + &[ + Token::Tuple { len: 3 }, + Token::U8(1), + Token::U8(2), + Token::U8(3), + Token::TupleEnd, + ], + "data did not match any variant of untagged enum Untagged", + ); +} + +#[test] +fn newtype_unit_and_empty_map() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Unit; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Message { + Unit(Unit), + Map(BTreeMap), + } + + assert_tokens( + &Message::Map(BTreeMap::new()), + &[Token::Map { len: Some(0) }, Token::MapEnd], + ); +} + +// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_newtype_struct +#[test] +fn newtype_struct() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeStruct(u32); + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum E { + Newtype(NewtypeStruct), + Null, + } + + let value = E::Newtype(NewtypeStruct(5)); + + // Content::Newtype case + assert_tokens( + &value, + &[ + Token::NewtypeStruct { + name: "NewtypeStruct", + }, + Token::U32(5), + ], + ); + + // _ case + assert_de_tokens(&value, &[Token::U32(5)]); +} + +mod newtype_enum { + use super::*; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Outer { + Inner(Inner), + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + enum Inner { + Unit, + Newtype(u8), + Tuple0(), + Tuple2(u8, u8), + Struct { f: u8 }, + EmptyStruct {}, + } + + // Reaches crate::private::de::content::VariantRefDeserializer::unit_variant + #[test] + fn unit() { + assert_tokens( + &Outer::Inner(Inner::Unit), + &[Token::UnitVariant { + name: "Inner", + variant: "Unit", + }], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::newtype_variant_seed + #[test] + fn newtype() { + assert_tokens( + &Outer::Inner(Inner::Newtype(1)), + &[ + Token::NewtypeVariant { + name: "Inner", + variant: "Newtype", + }, + Token::U8(1), + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant + #[test] + fn tuple0() { + assert_tokens( + &Outer::Inner(Inner::Tuple0()), + &[ + Token::TupleVariant { + name: "Inner", + variant: "Tuple0", + len: 0, + }, + Token::TupleVariantEnd, + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant + #[test] + fn tuple2() { + assert_tokens( + &Outer::Inner(Inner::Tuple2(1, 1)), + &[ + Token::TupleVariant { + name: "Inner", + variant: "Tuple2", + len: 2, + }, + Token::U8(1), + Token::U8(1), + Token::TupleVariantEnd, + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::struct_variant + // Content::Map case + #[test] + fn struct_from_map() { + assert_tokens( + &Outer::Inner(Inner::Struct { f: 1 }), + &[ + Token::StructVariant { + name: "Inner", + variant: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructVariantEnd, + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::struct_variant + // Content::Seq case + #[test] + fn struct_from_seq() { + assert_de_tokens( + &Outer::Inner(Inner::Struct { f: 1 }), + &[ + Token::Map { len: Some(1) }, + // tag + Token::Str("Struct"), + // content + Token::Seq { len: Some(1) }, + Token::U8(1), + Token::SeqEnd, + Token::MapEnd, + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::struct_variant + // Content::Map case + // Special case - empty map + #[test] + fn empty_struct_from_map() { + assert_de_tokens( + &Outer::Inner(Inner::EmptyStruct {}), + &[ + Token::Map { len: Some(1) }, + // tag + Token::Str("EmptyStruct"), + // content + Token::Map { len: Some(0) }, + Token::MapEnd, + Token::MapEnd, + ], + ); + } + + // Reaches crate::private::de::content::VariantRefDeserializer::struct_variant + // Content::Seq case + // Special case - empty seq + #[test] + fn empty_struct_from_seq() { + assert_de_tokens( + &Outer::Inner(Inner::EmptyStruct {}), + &[ + Token::Map { len: Some(1) }, + // tag + Token::Str("EmptyStruct"), + // content + Token::Seq { len: Some(0) }, + Token::SeqEnd, + Token::MapEnd, + ], + ); + } +} + +// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_option +mod with_optional_field { + use super::*; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Enum { + Struct { optional: Option }, + Null, + } + + #[test] + fn some() { + assert_tokens( + &Enum::Struct { optional: Some(42) }, + &[ + Token::Struct { + name: "Enum", + len: 1, + }, + Token::Str("optional"), + Token::Some, + Token::U32(42), + Token::StructEnd, + ], + ); + } + + #[test] + fn some_without_marker() { + assert_de_tokens( + &Enum::Struct { optional: Some(42) }, + &[ + Token::Struct { + name: "Enum", + len: 1, + }, + Token::Str("optional"), + Token::U32(42), + Token::StructEnd, + ], + ); + } + + #[test] + fn none() { + assert_tokens( + &Enum::Struct { optional: None }, + &[ + Token::Struct { + name: "Enum", + len: 1, + }, + Token::Str("optional"), + Token::None, + Token::StructEnd, + ], + ); + } + + #[test] + fn unit() { + assert_de_tokens( + &Enum::Struct { optional: None }, + &[ + Token::Map { len: None }, + Token::Str("optional"), + Token::Unit, + Token::MapEnd, + ], + ); + } +} + +#[test] +fn string_and_bytes() { + #[derive(Debug, PartialEq, Deserialize)] + #[serde(untagged)] + enum Untagged { + String { + string: String, + }, + Bytes { + #[serde(with = "bytes")] + bytes: Vec, + }, + } + + assert_de_tokens( + &Untagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { + string: "\0".to_owned(), + }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Seq { len: Some(1) }, + Token::U8(0), + Token::SeqEnd, + Token::StructEnd, + ], + ); +} + +#[test] +fn contains_flatten() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(untagged)] + enum Data { + A { + a: i32, + #[serde(flatten)] + flat: Flat, + }, + } + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Flat { + b: i32, + } + + let data = Data::A { + a: 0, + flat: Flat { b: 0 }, + }; + + assert_tokens( + &data, + &[ + Token::Map { len: None }, + Token::Str("a"), + Token::I32(0), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + ], + ); +} + +#[test] +fn contains_flatten_with_integer_key() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + pub enum Untagged { + Variant { + #[serde(flatten)] + map: BTreeMap, + }, + } + + 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] +fn expecting_message() { + #[derive(Deserialize)] + #[serde(untagged)] + #[serde(expecting = "something strange...")] + enum Enum { + Untagged, + } + + assert_de_tokens_error::(&[Token::Str("Untagged")], "something strange..."); +} diff --git a/test_suite/tests/test_gen.rs b/test_suite/tests/test_gen.rs index d8def742b..2c038ae8d 100644 --- a/test_suite/tests/test_gen.rs +++ b/test_suite/tests/test_gen.rs @@ -3,16 +3,31 @@ // types involved. #![deny(warnings)] -#![cfg_attr(feature = "unstable", feature(non_ascii_idents))] #![allow( + confusable_idents, unknown_lints, mixed_script_confusables, - clippy::trivially_copy_pass_by_ref + clippy::derive_partial_eq_without_eq, + clippy::extra_unused_type_parameters, + clippy::items_after_statements, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::must_use_candidate, + // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 + clippy::nonstandard_macro_braces, + clippy::ptr_arg, + clippy::too_many_lines, + clippy::trivially_copy_pass_by_ref, + clippy::type_repetition_in_bounds, + // We use lots of declarations inside function bodies to avoid conflicts, + // but they aren't used. We just want to make sure they compile. + dead_code, )] +#![deny(clippy::collection_is_never_read)] -use serde::de::DeserializeOwned; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - +use serde::de::{Deserialize, DeserializeOwned, Deserializer}; +use serde::ser::{Serialize, Serializer}; +use serde_derive::{Deserialize, Serialize}; use std::borrow::Cow; use std::marker::PhantomData; use std::option::Option as StdOption; @@ -247,6 +262,16 @@ fn test_gen() { } assert::>(); + type PhantomDataAlias = PhantomData; + + #[derive(Serialize, Deserialize)] + #[serde(bound = "")] + struct PhantomDataWrapper { + #[serde(default)] + field: PhantomDataAlias, + } + assert::>(); + #[derive(Serialize, Deserialize)] struct CowStr<'a>(Cow<'a, str>); assert::(); @@ -266,62 +291,61 @@ fn test_gen() { } assert::(); - #[cfg(feature = "unstable")] #[derive(Serialize, Deserialize)] - struct NonAsciiIdents { + pub struct NonAsciiIdents { σ: f64, } #[derive(Serialize, Deserialize)] - struct EmptyBraced {} + pub struct EmptyBraced {} #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct EmptyBracedDenyUnknown {} + pub struct EmptyBracedDenyUnknown {} #[derive(Serialize, Deserialize)] - struct BracedSkipAll { + pub struct BracedSkipAll { #[serde(skip_deserializing)] f: u8, } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct BracedSkipAllDenyUnknown { + pub struct BracedSkipAllDenyUnknown { #[serde(skip_deserializing)] f: u8, } #[derive(Serialize, Deserialize)] - struct EmptyTuple(); + pub struct EmptyTuple(); #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct EmptyTupleDenyUnknown(); + pub struct EmptyTupleDenyUnknown(); #[derive(Serialize, Deserialize)] - struct TupleSkipAll(#[serde(skip_deserializing)] u8); + pub struct TupleSkipAll(#[serde(skip_deserializing)] u8); #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8); + pub struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8); #[derive(Serialize, Deserialize)] - enum EmptyEnum {} + pub enum EmptyEnum {} #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - enum EmptyEnumDenyUnknown {} + pub enum EmptyEnumDenyUnknown {} #[derive(Serialize, Deserialize)] - enum EnumSkipAll { + pub enum EnumSkipAll { #[serde(skip_deserializing)] #[allow(dead_code)] Variant, } #[derive(Serialize, Deserialize)] - enum EmptyVariants { + pub enum EmptyVariants { Braced {}, Tuple(), BracedSkip { @@ -333,7 +357,7 @@ fn test_gen() { #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - enum EmptyVariantsDenyUnknown { + pub enum EmptyVariantsDenyUnknown { Braced {}, Tuple(), BracedSkip { @@ -345,21 +369,21 @@ fn test_gen() { #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct UnitDenyUnknown; + pub struct UnitDenyUnknown; #[derive(Serialize, Deserialize)] - struct EmptyArray { + pub struct EmptyArray { empty: [X; 0], } - enum Or { + pub enum Or { A(A), B(B), } #[derive(Serialize, Deserialize)] #[serde(untagged, remote = "Or")] - enum OrDef { + pub enum OrDef { A(A), B(B), } @@ -371,7 +395,7 @@ fn test_gen() { struct StrDef<'a>(&'a str); #[derive(Serialize, Deserialize)] - struct Remote<'a> { + pub struct Remote<'a> { #[serde(with = "OrDef")] or: Or, #[serde(borrow, with = "StrDef")] @@ -379,13 +403,13 @@ fn test_gen() { } #[derive(Serialize, Deserialize)] - enum BorrowVariant<'a> { + pub enum BorrowVariant<'a> { #[serde(borrow, with = "StrDef")] S(Str<'a>), } mod vis { - use serde::{Deserialize, Serialize}; + use serde_derive::{Deserialize, Serialize}; pub struct S; @@ -396,14 +420,14 @@ fn test_gen() { // This would not work if SDef::serialize / deserialize are private. #[derive(Serialize, Deserialize)] - struct RemoteVisibility { + pub struct RemoteVisibility { #[serde(with = "vis::SDef")] s: vis::S, } #[derive(Serialize, Deserialize)] #[serde(remote = "Self")] - struct RemoteSelf; + pub struct RemoteSelf; #[derive(Serialize, Deserialize)] enum ExternallyTaggedVariantWith { @@ -526,27 +550,46 @@ fn test_gen() { } assert::(); + #[derive(Serialize, Deserialize)] + pub struct Flatten { + #[serde(flatten)] + t: T, + } + #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] - struct FlattenDenyUnknown { + pub struct FlattenDenyUnknown { #[serde(flatten)] t: T, } #[derive(Serialize, Deserialize)] - struct StaticStrStruct<'a> { + pub struct SkipDeserializing { + #[serde(skip_deserializing)] + flat: T, + } + + #[derive(Serialize, Deserialize)] + #[serde(deny_unknown_fields)] + pub struct SkipDeserializingDenyUnknown { + #[serde(skip_deserializing)] + flat: T, + } + + #[derive(Serialize, Deserialize)] + pub struct StaticStrStruct<'a> { a: &'a str, b: &'static str, } #[derive(Serialize, Deserialize)] - struct StaticStrTupleStruct<'a>(&'a str, &'static str); + pub struct StaticStrTupleStruct<'a>(&'a str, &'static str); #[derive(Serialize, Deserialize)] - struct StaticStrNewtypeStruct(&'static str); + pub struct StaticStrNewtypeStruct(&'static str); #[derive(Serialize, Deserialize)] - enum StaticStrEnum<'a> { + pub enum StaticStrEnum<'a> { Struct { a: &'a str, b: &'static str }, Tuple(&'a str, &'static str), Newtype(&'static str), @@ -617,9 +660,10 @@ fn test_gen() { mod restricted { mod inner { - use serde::{Deserialize, Serialize}; + use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] + #[allow(dead_code)] struct Restricted { pub(super) a: usize, pub(in super::inner) b: usize, @@ -629,7 +673,7 @@ fn test_gen() { #[derive(Deserialize)] #[serde(tag = "t", content = "c")] - enum AdjacentlyTaggedVoid {} + pub enum AdjacentlyTaggedVoid {} #[derive(Serialize, Deserialize)] enum SkippedVariant { @@ -642,13 +686,14 @@ fn test_gen() { assert::>(); #[derive(Deserialize)] - struct ImpliciltyBorrowedOption<'a> { + pub struct ImplicitlyBorrowedOption<'a> { option: std::option::Option<&'a str>, } #[derive(Serialize, Deserialize)] #[serde(untagged)] - enum UntaggedNewtypeVariantWith { + #[allow(dead_code)] + pub enum UntaggedNewtypeVariantWith { Newtype( #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] @@ -658,7 +703,8 @@ fn test_gen() { #[derive(Serialize, Deserialize)] #[serde(transparent)] - struct TransparentWith { + #[allow(dead_code)] + pub struct TransparentWith { #[serde(serialize_with = "ser_x")] #[serde(deserialize_with = "de_x")] x: X, @@ -666,39 +712,61 @@ fn test_gen() { #[derive(Deserialize)] #[serde(untagged)] - enum UntaggedWithBorrow<'a> { - Single(#[serde(borrow)] RelObject<'a>), - Many(#[serde(borrow)] Vec>), + #[allow(dead_code)] + pub enum UntaggedWithBorrow<'a> { + Single( + #[serde(borrow)] + #[allow(dead_code)] + RelObject<'a>, + ), + Many( + #[serde(borrow)] + #[allow(dead_code)] + Vec>, + ), } #[derive(Deserialize)] - struct RelObject<'a> { + pub struct RelObject<'a> { ty: &'a str, id: String, } #[derive(Serialize, Deserialize)] - struct FlattenSkipSerializing { + pub struct FlattenSkipSerializing { #[serde(flatten, skip_serializing)] #[allow(dead_code)] flat: T, } #[derive(Serialize, Deserialize)] - struct FlattenSkipSerializingIf { + pub struct FlattenSkipSerializingIf { #[serde(flatten, skip_serializing_if = "StdOption::is_none")] flat: StdOption, } #[derive(Serialize, Deserialize)] - struct FlattenSkipDeserializing { + pub struct FlattenSkipDeserializing { #[serde(flatten, skip_deserializing)] flat: T, } + #[derive(Serialize, Deserialize)] + #[serde(untagged)] + pub enum Inner { + Builder { + s: T, + #[serde(flatten)] + o: T, + }, + Default { + s: T, + }, + } + // https://github.com/serde-rs/serde/issues/1804 #[derive(Serialize, Deserialize)] - enum Message { + pub enum Message { #[serde(skip)] #[allow(dead_code)] String(String), @@ -707,7 +775,8 @@ fn test_gen() { } #[derive(Serialize)] - #[repr(packed)] + #[repr(C, packed)] + #[allow(dead_code)] struct Packed { x: u8, y: u16, @@ -716,13 +785,37 @@ fn test_gen() { macro_rules! deriving { ($field:ty) => { #[derive(Deserialize)] - struct MacroRules<'a> { + pub struct MacroRules<'a> { field: $field, } }; } deriving!(&'a str); + + macro_rules! mac { + ($($tt:tt)*) => { + $($tt)* + }; + } + + #[derive(Deserialize)] + pub struct BorrowLifetimeInsideMacro<'a> { + #[serde(borrow = "'a")] + pub f: mac!(Cow<'a, str>), + } + + #[derive(Serialize)] + pub struct Struct { + #[serde(serialize_with = "vec_first_element")] + pub vec: Vec, + } + + assert_ser::(); + + #[derive(Deserialize)] + #[serde(bound(deserialize = "[&'de str; N]: Copy"))] + pub struct GenericUnitStruct; } ////////////////////////////////////////////////////////////////////////// @@ -796,3 +889,72 @@ where pub fn is_zero(n: &u8) -> bool { *n == 0 } + +fn vec_first_element(vec: &[T], serializer: S) -> StdResult +where + T: Serialize, + S: Serializer, +{ + vec.first().serialize(serializer) +} + +////////////////////////////////////////////////////////////////////////// + +#[derive(Debug, PartialEq, Deserialize)] +#[serde(tag = "tag")] +pub enum InternallyTagged { + #[serde(deserialize_with = "deserialize_generic")] + Unit, + + #[serde(deserialize_with = "deserialize_generic")] + Newtype(i32), + + #[serde(deserialize_with = "deserialize_generic")] + Struct { f1: String, f2: u8 }, +} + +fn deserialize_generic<'de, T, D>(deserializer: D) -> StdResult +where + T: Deserialize<'de>, + D: Deserializer<'de>, +{ + T::deserialize(deserializer) +} + +////////////////////////////////////////////////////////////////////////// + +#[repr(C, packed)] +pub struct RemotePacked { + pub a: u16, + pub b: u32, +} + +#[derive(Serialize)] +#[repr(C, packed)] +#[serde(remote = "RemotePacked")] +pub struct RemotePackedDef { + a: u16, + b: u32, +} + +impl Drop for RemotePackedDef { + fn drop(&mut self) {} +} + +#[repr(C, packed)] +pub struct RemotePackedNonCopy { + pub a: u16, + pub b: String, +} + +#[derive(Deserialize)] +#[repr(C, packed)] +#[serde(remote = "RemotePackedNonCopy")] +pub struct RemotePackedNonCopyDef { + a: u16, + b: String, +} + +impl Drop for RemotePackedNonCopyDef { + fn drop(&mut self) {} +} diff --git a/test_suite/tests/test_identifier.rs b/test_suite/tests/test_identifier.rs index eba7d4dac..4e141414b 100644 --- a/test_suite/tests/test_identifier.rs +++ b/test_suite/tests/test_identifier.rs @@ -1,72 +1,188 @@ -use serde::Deserialize; -use serde_test::{assert_de_tokens, Token}; +//! Tests for `#[serde(field_identifier)]` and `#[serde(variant_identifier)]` + +#![allow(clippy::derive_partial_eq_without_eq)] + +use serde_derive::Deserialize; +use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; + +mod variant_identifier { + use super::*; -#[test] -fn test_variant_identifier() { #[derive(Deserialize, Debug, PartialEq)] #[serde(variant_identifier)] enum V { Aaa, + #[serde(alias = "Ccc", alias = "Ddd")] Bbb, } - assert_de_tokens(&V::Aaa, &[Token::U8(0)]); - assert_de_tokens(&V::Aaa, &[Token::U16(0)]); - assert_de_tokens(&V::Aaa, &[Token::U32(0)]); - assert_de_tokens(&V::Aaa, &[Token::U64(0)]); - assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]); - assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]); -} + #[test] + fn variant1() { + assert_de_tokens(&V::Aaa, &[Token::U8(0)]); + assert_de_tokens(&V::Aaa, &[Token::U16(0)]); + assert_de_tokens(&V::Aaa, &[Token::U32(0)]); + assert_de_tokens(&V::Aaa, &[Token::U64(0)]); + assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]); + assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]); + } -#[test] -fn test_field_identifier() { - #[derive(Deserialize, Debug, PartialEq)] - #[serde(field_identifier, rename_all = "snake_case")] - enum F { - Aaa, - Bbb, + #[test] + fn aliases() { + assert_de_tokens(&V::Bbb, &[Token::U8(1)]); + assert_de_tokens(&V::Bbb, &[Token::U16(1)]); + assert_de_tokens(&V::Bbb, &[Token::U32(1)]); + assert_de_tokens(&V::Bbb, &[Token::U64(1)]); + + assert_de_tokens(&V::Bbb, &[Token::Str("Bbb")]); + assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Bbb")]); + + assert_de_tokens(&V::Bbb, &[Token::Str("Ccc")]); + assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ccc")]); + + assert_de_tokens(&V::Bbb, &[Token::Str("Ddd")]); + assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ddd")]); } - assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]); - assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]); + #[test] + fn unknown() { + assert_de_tokens_error::( + &[Token::U8(42)], + "invalid value: integer `42`, expected variant index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U16(42)], + "invalid value: integer `42`, expected variant index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U32(42)], + "invalid value: integer `42`, expected variant index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U64(42)], + "invalid value: integer `42`, expected variant index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::Str("Unknown")], + "unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`", + ); + assert_de_tokens_error::( + &[Token::Bytes(b"Unknown")], + "unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`", + ); + } } -#[test] -fn test_unit_fallthrough() { +mod field_identifier { + use super::*; + #[derive(Deserialize, Debug, PartialEq)] #[serde(field_identifier, rename_all = "snake_case")] enum F { Aaa, + #[serde(alias = "ccc", alias = "ddd")] Bbb, - #[serde(other)] - Other, } - assert_de_tokens(&F::Other, &[Token::Str("x")]); -} + #[test] + fn field1() { + assert_de_tokens(&F::Aaa, &[Token::U8(0)]); + assert_de_tokens(&F::Aaa, &[Token::U16(0)]); + assert_de_tokens(&F::Aaa, &[Token::U32(0)]); + assert_de_tokens(&F::Aaa, &[Token::U64(0)]); + assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]); + assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]); + } -#[test] -fn test_newtype_fallthrough() { - #[derive(Deserialize, Debug, PartialEq)] - #[serde(field_identifier, rename_all = "snake_case")] - enum F { - Aaa, - Bbb, - Other(String), + #[test] + fn aliases() { + assert_de_tokens(&F::Bbb, &[Token::U8(1)]); + assert_de_tokens(&F::Bbb, &[Token::U16(1)]); + assert_de_tokens(&F::Bbb, &[Token::U32(1)]); + assert_de_tokens(&F::Bbb, &[Token::U64(1)]); + + assert_de_tokens(&F::Bbb, &[Token::Str("bbb")]); + assert_de_tokens(&F::Bbb, &[Token::Bytes(b"bbb")]); + + assert_de_tokens(&F::Bbb, &[Token::Str("ccc")]); + assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ccc")]); + + assert_de_tokens(&F::Bbb, &[Token::Str("ddd")]); + assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ddd")]); } - assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); -} + #[test] + fn unknown() { + assert_de_tokens_error::( + &[Token::U8(42)], + "invalid value: integer `42`, expected field index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U16(42)], + "invalid value: integer `42`, expected field index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U32(42)], + "invalid value: integer `42`, expected field index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::U64(42)], + "invalid value: integer `42`, expected field index 0 <= i < 2", + ); + assert_de_tokens_error::( + &[Token::Str("unknown")], + "unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`", + ); + assert_de_tokens_error::( + &[Token::Bytes(b"unknown")], + "unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`", + ); + } -#[test] -fn test_newtype_fallthrough_generic() { - #[derive(Deserialize, Debug, PartialEq)] - #[serde(field_identifier, rename_all = "snake_case")] - enum F { - Aaa, - Bbb, - Other(T), + #[test] + fn unit_fallthrough() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(field_identifier, rename_all = "snake_case")] + enum F { + Aaa, + Bbb, + #[serde(other)] + Other, + } + + assert_de_tokens(&F::Other, &[Token::U8(42)]); + assert_de_tokens(&F::Other, &[Token::U16(42)]); + assert_de_tokens(&F::Other, &[Token::U32(42)]); + assert_de_tokens(&F::Other, &[Token::U64(42)]); + assert_de_tokens(&F::Other, &[Token::Str("x")]); } - assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); + #[test] + fn newtype_fallthrough() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(field_identifier, rename_all = "snake_case")] + enum F { + Aaa, + Bbb, + Other(String), + } + + assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); + } + + #[test] + fn newtype_fallthrough_generic() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(field_identifier, rename_all = "snake_case")] + enum F { + Aaa, + Bbb, + Other(T), + } + + assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]); + assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]); + assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]); + assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]); + assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); + } } diff --git a/test_suite/tests/test_ignored_any.rs b/test_suite/tests/test_ignored_any.rs index 921cdfc79..955b7974e 100644 --- a/test_suite/tests/test_ignored_any.rs +++ b/test_suite/tests/test_ignored_any.rs @@ -1,8 +1,12 @@ +#![allow(clippy::derive_partial_eq_without_eq)] + use serde::de::value::{Error, MapDeserializer, SeqDeserializer}; use serde::de::{ - DeserializeSeed, EnumAccess, IgnoredAny, IntoDeserializer, VariantAccess, Visitor, + Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, IntoDeserializer, + VariantAccess, Visitor, }; -use serde::{forward_to_deserialize_any, Deserialize, Deserializer}; +use serde::forward_to_deserialize_any; +use serde_derive::Deserialize; #[derive(PartialEq, Debug, Deserialize)] enum Target { diff --git a/test_suite/tests/test_macros.rs b/test_suite/tests/test_macros.rs index c6c0c1785..6b2fc4c5d 100644 --- a/test_suite/tests/test_macros.rs +++ b/test_suite/tests/test_macros.rs @@ -1,14 +1,13 @@ #![deny(trivial_numeric_casts)] -#![allow(clippy::redundant_field_names)] - -mod bytes; - -use serde::{Deserialize, Serialize}; -use serde_test::{ - assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token, -}; - -use std::collections::BTreeMap; +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::enum_variant_names, + clippy::redundant_field_names, + clippy::too_many_lines +)] + +use serde_derive::{Deserialize, Serialize}; +use serde_test::{assert_de_tokens, assert_ser_tokens, assert_tokens, Token}; use std::marker::PhantomData; // That tests that the derived Serialize implementation doesn't trigger @@ -429,51 +428,6 @@ fn test_generic_newtype_struct() { ); } -#[test] -fn test_untagged_newtype_struct() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(untagged)] - enum E { - Newtype(GenericNewTypeStruct), - Null, - } - - assert_tokens( - &E::Newtype(GenericNewTypeStruct(5u32)), - &[ - Token::NewtypeStruct { - name: "GenericNewTypeStruct", - }, - Token::U32(5), - ], - ); -} - -#[test] -fn test_adjacently_tagged_newtype_struct() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "t", content = "c")] - enum E { - Newtype(GenericNewTypeStruct), - Null, - } - - assert_de_tokens( - &E::Newtype(GenericNewTypeStruct(5u32)), - &[ - Token::Struct { name: "E", len: 2 }, - Token::Str("c"), - Token::NewtypeStruct { - name: "GenericNewTypeStruct", - }, - Token::U32(5), - Token::Str("t"), - Token::Str("Newtype"), - Token::StructEnd, - ], - ); -} - #[test] fn test_generic_tuple_struct() { assert_tokens( @@ -599,1309 +553,313 @@ fn test_enum_state_field() { } #[test] -fn test_untagged_enum() { +fn test_internally_tagged_struct() { #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(untagged)] - enum Untagged { - A { a: u8 }, - B { b: u8 }, - C, - D(u8), - E(String), - F(u8, u8), + #[serde(tag = "type")] + pub struct Struct { + a: u8, } assert_tokens( - &Untagged::A { a: 1 }, + &Struct { a: 1 }, &[ Token::Struct { - name: "Untagged", - len: 1, + name: "Struct", + len: 2, }, + Token::Str("type"), + Token::Str("Struct"), Token::Str("a"), Token::U8(1), Token::StructEnd, ], ); - assert_tokens( - &Untagged::B { b: 2 }, + assert_de_tokens( + &Struct { a: 1 }, &[ Token::Struct { - name: "Untagged", + name: "Struct", len: 1, }, - Token::Str("b"), - Token::U8(2), + Token::Str("a"), + Token::U8(1), Token::StructEnd, ], ); +} - // Serializes to unit, deserializes from either depending on format's - // preference. - assert_tokens(&Untagged::C, &[Token::Unit]); - assert_de_tokens(&Untagged::C, &[Token::None]); - - assert_tokens(&Untagged::D(4), &[Token::U8(4)]); - assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]); +#[test] +fn test_internally_tagged_braced_struct_with_zero_fields() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "type")] + struct S {} assert_tokens( - &Untagged::F(1, 2), - &[ - Token::Tuple { len: 2 }, - Token::U8(1), - Token::U8(2), - Token::TupleEnd, - ], - ); - - assert_de_tokens_error::( - &[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd], - "data did not match any variant of untagged enum Untagged", - ); - - assert_de_tokens_error::( + &S {}, &[ - Token::Tuple { len: 3 }, - Token::U8(1), - Token::U8(2), - Token::U8(3), - Token::TupleEnd, + Token::Struct { name: "S", len: 1 }, + Token::Str("type"), + Token::Str("S"), + Token::StructEnd, ], - "data did not match any variant of untagged enum Untagged", ); } #[test] -fn test_internally_tagged_enum() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Newtype(BTreeMap); - +fn test_internally_tagged_struct_with_flattened_field() { #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Struct { - f: u8, + #[serde(tag = "tag_struct")] + pub struct Struct { + #[serde(flatten)] + pub flat: Enum, } #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "type")] - enum InternallyTagged { - A { a: u8 }, - B, - C(BTreeMap), - D(Newtype), - E(Struct), + #[serde(tag = "tag_enum", content = "content")] + pub enum Enum { + A(u64), } assert_tokens( - &InternallyTagged::A { a: 1 }, + &Struct { flat: Enum::A(0) }, &[ - Token::Struct { - name: "InternallyTagged", - len: 2, + Token::Map { len: None }, + Token::Str("tag_struct"), + Token::Str("Struct"), + Token::Str("tag_enum"), + Token::UnitVariant { + name: "Enum", + variant: "A", }, - Token::Str("type"), - Token::Str("A"), - Token::Str("a"), - Token::U8(1), - Token::StructEnd, + Token::Str("content"), + Token::U64(0), + Token::MapEnd, ], ); assert_de_tokens( - &InternallyTagged::A { a: 1 }, + &Struct { flat: Enum::A(0) }, &[ - Token::Seq { len: Some(2) }, + Token::Map { len: None }, + Token::Str("tag_enum"), Token::Str("A"), - Token::U8(1), - Token::SeqEnd, + Token::Str("content"), + Token::U64(0), + Token::MapEnd, ], ); +} + +#[test] +fn test_rename_all() { + #[derive(Serialize, Deserialize, Debug, PartialEq)] + #[serde(rename_all = "snake_case")] + enum E { + #[serde(rename_all = "camelCase")] + Serialize { + serialize: bool, + serialize_seq: bool, + }, + #[serde(rename_all = "kebab-case")] + SerializeSeq { + serialize: bool, + serialize_seq: bool, + }, + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + SerializeMap { + serialize: bool, + serialize_seq: bool, + }, + } + + #[derive(Serialize, Deserialize, Debug, PartialEq)] + #[serde(rename_all = "PascalCase")] + struct S { + serialize: bool, + serialize_seq: bool, + } + + #[derive(Serialize, Deserialize, Debug, PartialEq)] + #[serde(rename_all = "SCREAMING-KEBAB-CASE")] + struct ScreamingKebab { + serialize: bool, + serialize_seq: bool, + } assert_tokens( - &InternallyTagged::B, + &E::Serialize { + serialize: true, + serialize_seq: true, + }, &[ - Token::Struct { - name: "InternallyTagged", - len: 1, + Token::StructVariant { + name: "E", + variant: "serialize", + len: 2, }, - Token::Str("type"), - Token::Str("B"), - Token::StructEnd, + Token::Str("serialize"), + Token::Bool(true), + Token::Str("serializeSeq"), + Token::Bool(true), + Token::StructVariantEnd, ], ); - assert_de_tokens( - &InternallyTagged::B, - &[Token::Seq { len: Some(1) }, Token::Str("B"), Token::SeqEnd], - ); - assert_tokens( - &InternallyTagged::C(BTreeMap::new()), + &E::SerializeSeq { + serialize: true, + serialize_seq: true, + }, &[ - Token::Map { len: Some(1) }, - Token::Str("type"), - Token::Str("C"), - Token::MapEnd, + Token::StructVariant { + name: "E", + variant: "serialize_seq", + len: 2, + }, + Token::Str("serialize"), + Token::Bool(true), + Token::Str("serialize-seq"), + Token::Bool(true), + Token::StructVariantEnd, ], ); - assert_de_tokens_error::( + assert_tokens( + &E::SerializeMap { + serialize: true, + serialize_seq: true, + }, &[ - Token::Seq { len: Some(2) }, - Token::Str("C"), - Token::Map { len: Some(0) }, - Token::MapEnd, - Token::SeqEnd, + Token::StructVariant { + name: "E", + variant: "serialize_map", + len: 2, + }, + Token::Str("SERIALIZE"), + Token::Bool(true), + Token::Str("SERIALIZE_SEQ"), + Token::Bool(true), + Token::StructVariantEnd, ], - "invalid type: sequence, expected a map", ); assert_tokens( - &InternallyTagged::D(Newtype(BTreeMap::new())), + &S { + serialize: true, + serialize_seq: true, + }, &[ - Token::Map { len: Some(1) }, - Token::Str("type"), - Token::Str("D"), - Token::MapEnd, + Token::Struct { name: "S", len: 2 }, + Token::Str("Serialize"), + Token::Bool(true), + Token::Str("SerializeSeq"), + Token::Bool(true), + Token::StructEnd, ], ); assert_tokens( - &InternallyTagged::E(Struct { f: 6 }), + &ScreamingKebab { + serialize: true, + serialize_seq: true, + }, &[ Token::Struct { - name: "Struct", + name: "ScreamingKebab", len: 2, }, - Token::Str("type"), - Token::Str("E"), - Token::Str("f"), - Token::U8(6), + Token::Str("SERIALIZE"), + Token::Bool(true), + Token::Str("SERIALIZE-SEQ"), + Token::Bool(true), Token::StructEnd, ], ); - - assert_de_tokens( - &InternallyTagged::E(Struct { f: 6 }), - &[ - Token::Seq { len: Some(2) }, - Token::Str("E"), - Token::U8(6), - Token::SeqEnd, - ], - ); - - assert_de_tokens_error::( - &[Token::Map { len: Some(0) }, Token::MapEnd], - "missing field `type`", - ); - - assert_de_tokens_error::( - &[ - Token::Map { len: Some(1) }, - Token::Str("type"), - Token::Str("Z"), - Token::MapEnd, - ], - "unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`", - ); } #[test] -fn test_internally_tagged_bytes() { - #[derive(Debug, PartialEq, Deserialize)] - #[serde(tag = "type")] - enum InternallyTagged { - String { - string: String, +fn test_rename_all_fields() { + #[derive(Serialize, Deserialize, Debug, PartialEq)] + #[serde(rename_all_fields = "kebab-case")] + enum E { + V1, + V2(bool), + V3 { + a_field: bool, + another_field: bool, + #[serde(rename = "last-field")] + yet_another_field: bool, }, - Bytes { - #[serde(with = "bytes")] - bytes: Vec, + #[serde(rename_all = "snake_case")] + V4 { + a_field: bool, }, } - assert_de_tokens( - &InternallyTagged::String { - string: "\0".to_owned(), + assert_tokens( + &E::V3 { + a_field: true, + another_field: true, + yet_another_field: true, }, &[ - Token::Struct { - name: "String", - len: 2, + Token::StructVariant { + name: "E", + variant: "V3", + len: 3, }, - Token::Str("type"), - Token::Str("String"), - Token::Str("string"), - Token::Str("\0"), - Token::StructEnd, + Token::Str("a-field"), + Token::Bool(true), + Token::Str("another-field"), + Token::Bool(true), + Token::Str("last-field"), + Token::Bool(true), + Token::StructVariantEnd, ], ); - assert_de_tokens( - &InternallyTagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "String", - len: 2, - }, - Token::Str("type"), - Token::Str("String"), - Token::Str("string"), - Token::String("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "String", - len: 2, - }, - Token::Str("type"), - Token::Str("String"), - Token::Str("string"), - Token::Bytes(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "String", - len: 2, - }, - Token::Str("type"), - Token::Str("String"), - Token::Str("string"), - Token::ByteBuf(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Bytes", - len: 2, - }, - Token::Str("type"), - Token::Str("Bytes"), - Token::Str("bytes"), - Token::Str("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Bytes", - len: 2, - }, - Token::Str("type"), - Token::Str("Bytes"), - Token::Str("bytes"), - Token::String("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Bytes", - len: 2, - }, - Token::Str("type"), - Token::Str("Bytes"), - Token::Str("bytes"), - Token::Bytes(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Bytes", - len: 2, - }, - Token::Str("type"), - Token::Str("Bytes"), - Token::Str("bytes"), - Token::ByteBuf(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &InternallyTagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Bytes", - len: 2, - }, - Token::Str("type"), - Token::Str("Bytes"), - Token::Str("bytes"), - Token::Seq { len: Some(1) }, - Token::U8(0), - Token::SeqEnd, - Token::StructEnd, - ], - ); -} - -#[test] -fn test_internally_tagged_struct_variant_containing_unit_variant() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - pub enum Level { - Info, - } - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "action")] - pub enum Message { - Log { level: Level }, - } - - assert_de_tokens( - &Message::Log { level: Level::Info }, - &[ - Token::Struct { - name: "Message", - len: 2, - }, - Token::Str("action"), - Token::Str("Log"), - Token::Str("level"), - Token::BorrowedStr("Info"), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_internally_tagged_borrow() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "type")] - pub enum Input<'a> { - Package { name: &'a str }, - } - - assert_tokens( - &Input::Package { name: "borrowed" }, - &[ - Token::Struct { - name: "Input", - len: 2, - }, - Token::BorrowedStr("type"), - Token::BorrowedStr("Package"), - Token::BorrowedStr("name"), - Token::BorrowedStr("borrowed"), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_adjacently_tagged_enum() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "t", content = "c")] - enum AdjacentlyTagged { - Unit, - Newtype(T), - Tuple(u8, u8), - Struct { f: u8 }, - } - - // unit with no content - assert_ser_tokens( - &AdjacentlyTagged::Unit::, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 1, - }, - Token::Str("t"), - Token::Str("Unit"), - Token::StructEnd, - ], - ); - - // unit with no content - assert_de_tokens( - &AdjacentlyTagged::Unit::, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Unit"), - Token::StructEnd, - ], - ); - - // unit with tag first - assert_de_tokens( - &AdjacentlyTagged::Unit::, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Unit"), - Token::Str("c"), - Token::Unit, - Token::StructEnd, - ], - ); - - // unit with content first - assert_de_tokens( - &AdjacentlyTagged::Unit::, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("c"), - Token::Unit, - Token::Str("t"), - Token::Str("Unit"), - Token::StructEnd, - ], - ); - - // unit with excess content (f, g, h) - assert_de_tokens( - &AdjacentlyTagged::Unit::, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("f"), - Token::Unit, - Token::Str("t"), - Token::Str("Unit"), - Token::Str("g"), - Token::Unit, - Token::Str("c"), - Token::Unit, - Token::Str("h"), - Token::Unit, - Token::StructEnd, - ], - ); - - // newtype with tag first - assert_tokens( - &AdjacentlyTagged::Newtype::(1), - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Newtype"), - Token::Str("c"), - Token::U8(1), - Token::StructEnd, - ], - ); - - // newtype with content first - assert_de_tokens( - &AdjacentlyTagged::Newtype::(1), - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("c"), - Token::U8(1), - Token::Str("t"), - Token::Str("Newtype"), - Token::StructEnd, - ], - ); - - // optional newtype with no content field - assert_de_tokens( - &AdjacentlyTagged::Newtype::>(None), - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 1, - }, - Token::Str("t"), - Token::Str("Newtype"), - Token::StructEnd, - ], - ); - - // tuple with tag first - assert_tokens( - &AdjacentlyTagged::Tuple::(1, 1), - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Tuple"), - Token::Str("c"), - Token::Tuple { len: 2 }, - Token::U8(1), - Token::U8(1), - Token::TupleEnd, - Token::StructEnd, - ], - ); - - // tuple with content first - assert_de_tokens( - &AdjacentlyTagged::Tuple::(1, 1), - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("c"), - Token::Tuple { len: 2 }, - Token::U8(1), - Token::U8(1), - Token::TupleEnd, - Token::Str("t"), - Token::Str("Tuple"), - Token::StructEnd, - ], - ); - - // struct with tag first - assert_tokens( - &AdjacentlyTagged::Struct:: { f: 1 }, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Struct"), - Token::Str("c"), - Token::Struct { - name: "Struct", - len: 1, - }, - Token::Str("f"), - Token::U8(1), - Token::StructEnd, - Token::StructEnd, - ], - ); - - // struct with content first - assert_de_tokens( - &AdjacentlyTagged::Struct:: { f: 1 }, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("c"), - Token::Struct { - name: "Struct", - len: 1, - }, - Token::Str("f"), - Token::U8(1), - Token::StructEnd, - Token::Str("t"), - Token::Str("Struct"), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_adjacently_tagged_enum_deny_unknown_fields() { - #[derive(Debug, PartialEq, Deserialize)] - #[serde(tag = "t", content = "c", deny_unknown_fields)] - enum AdjacentlyTagged { - Unit, - } - - assert_de_tokens( - &AdjacentlyTagged::Unit, - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Unit"), - Token::Str("c"), - Token::Unit, - Token::StructEnd, - ], - ); - - assert_de_tokens_error::( - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("t"), - Token::Str("Unit"), - Token::Str("c"), - Token::Unit, - Token::Str("h"), - ], - r#"invalid value: string "h", expected "t" or "c""#, - ); - - assert_de_tokens_error::( - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("h"), - ], - r#"invalid value: string "h", expected "t" or "c""#, - ); - - assert_de_tokens_error::( - &[ - Token::Struct { - name: "AdjacentlyTagged", - len: 2, - }, - Token::Str("c"), - Token::Unit, - Token::Str("h"), - ], - r#"invalid value: string "h", expected "t" or "c""#, - ); -} - -#[test] -fn test_enum_in_internally_tagged_enum() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "type")] - enum Outer { - Inner(Inner), - } - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - enum Inner { - Unit, - Newtype(u8), - Tuple(u8, u8), - Struct { f: u8 }, - } - - assert_tokens( - &Outer::Inner(Inner::Unit), - &[ - Token::Map { len: Some(2) }, - Token::Str("type"), - Token::Str("Inner"), - Token::Str("Unit"), - Token::Unit, - Token::MapEnd, - ], - ); - - assert_tokens( - &Outer::Inner(Inner::Newtype(1)), - &[ - Token::Map { len: Some(2) }, - Token::Str("type"), - Token::Str("Inner"), - Token::Str("Newtype"), - Token::U8(1), - Token::MapEnd, - ], - ); - - assert_tokens( - &Outer::Inner(Inner::Tuple(1, 1)), - &[ - Token::Map { len: Some(2) }, - Token::Str("type"), - Token::Str("Inner"), - Token::Str("Tuple"), - Token::TupleStruct { - name: "Tuple", - len: 2, - }, - Token::U8(1), - Token::U8(1), - Token::TupleStructEnd, - Token::MapEnd, - ], - ); - - assert_tokens( - &Outer::Inner(Inner::Struct { f: 1 }), - &[ - Token::Map { len: Some(2) }, - Token::Str("type"), - Token::Str("Inner"), - Token::Str("Struct"), - Token::Struct { - name: "Struct", - len: 1, - }, - Token::Str("f"), - Token::U8(1), - Token::StructEnd, - Token::MapEnd, - ], - ); -} - -#[test] -fn test_internally_tagged_struct() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "type")] - pub struct Struct { - a: u8, - } - - assert_tokens( - &Struct { a: 1 }, - &[ - Token::Struct { - name: "Struct", - len: 2, - }, - Token::Str("type"), - Token::Str("Struct"), - Token::Str("a"), - Token::U8(1), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Struct { a: 1 }, - &[ - Token::Struct { - name: "Struct", - len: 1, - }, - Token::Str("a"), - Token::U8(1), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_internally_tagged_braced_struct_with_zero_fields() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "type")] - struct S {} - - assert_tokens( - &S {}, - &[ - Token::Struct { name: "S", len: 1 }, - Token::Str("type"), - Token::Str("S"), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_internally_tagged_struct_with_flattened_field() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "tag_struct")] - pub struct Struct { - #[serde(flatten)] - pub flat: Enum, - } - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "tag_enum", content = "content")] - pub enum Enum { - A(u64), - } - - assert_tokens( - &Struct { flat: Enum::A(0) }, - &[ - Token::Map { len: None }, - Token::Str("tag_struct"), - Token::Str("Struct"), - Token::Str("tag_enum"), - Token::Str("A"), - Token::Str("content"), - Token::U64(0), - Token::MapEnd, - ], - ); - - assert_de_tokens( - &Struct { flat: Enum::A(0) }, - &[ - Token::Map { len: None }, - Token::Str("tag_enum"), - Token::Str("A"), - Token::Str("content"), - Token::U64(0), - Token::MapEnd, - ], - ); -} - -#[test] -fn test_untagged_enum_with_flattened_integer_key() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(untagged)] - pub enum Untagged { - Variant { - #[serde(flatten)] - map: BTreeMap, - }, - } - - 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] -fn test_enum_in_untagged_enum() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(untagged)] - enum Outer { - Inner(Inner), - } - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - enum Inner { - Unit, - Newtype(u8), - Tuple(u8, u8), - Struct { f: u8 }, - } - - assert_tokens( - &Outer::Inner(Inner::Unit), - &[Token::UnitVariant { - name: "Inner", - variant: "Unit", - }], - ); - - assert_tokens( - &Outer::Inner(Inner::Newtype(1)), - &[ - Token::NewtypeVariant { - name: "Inner", - variant: "Newtype", - }, - Token::U8(1), - ], - ); - - assert_tokens( - &Outer::Inner(Inner::Tuple(1, 1)), - &[ - Token::TupleVariant { - name: "Inner", - variant: "Tuple", - len: 2, - }, - Token::U8(1), - Token::U8(1), - Token::TupleVariantEnd, - ], - ); - - assert_tokens( - &Outer::Inner(Inner::Struct { f: 1 }), - &[ - Token::StructVariant { - name: "Inner", - variant: "Struct", - len: 1, - }, - Token::Str("f"), - Token::U8(1), - Token::StructVariantEnd, - ], - ); -} - -#[test] -fn test_untagged_bytes() { - #[derive(Debug, PartialEq, Deserialize)] - #[serde(untagged)] - enum Untagged { - String { - string: String, - }, - Bytes { - #[serde(with = "bytes")] - bytes: Vec, - }, - } - - assert_de_tokens( - &Untagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("string"), - Token::Str("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("string"), - Token::String("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("string"), - Token::Bytes(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::String { - string: "\0".to_owned(), - }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("string"), - Token::ByteBuf(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("bytes"), - Token::Str("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("bytes"), - Token::String("\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("bytes"), - Token::Bytes(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("bytes"), - Token::ByteBuf(b"\0"), - Token::StructEnd, - ], - ); - - assert_de_tokens( - &Untagged::Bytes { bytes: vec![0] }, - &[ - Token::Struct { - name: "Untagged", - len: 1, - }, - Token::Str("bytes"), - Token::Seq { len: Some(1) }, - Token::U8(0), - Token::SeqEnd, - Token::StructEnd, - ], - ); -} - -#[test] -fn test_rename_all() { - #[derive(Serialize, Deserialize, Debug, PartialEq)] - #[serde(rename_all = "snake_case")] - enum E { - #[serde(rename_all = "camelCase")] - Serialize { - serialize: bool, - serialize_seq: bool, - }, - #[serde(rename_all = "kebab-case")] - SerializeSeq { - serialize: bool, - serialize_seq: bool, - }, - #[serde(rename_all = "SCREAMING_SNAKE_CASE")] - SerializeMap { - serialize: bool, - serialize_seq: bool, - }, - } - - #[derive(Serialize, Deserialize, Debug, PartialEq)] - #[serde(rename_all = "PascalCase")] - struct S { - serialize: bool, - serialize_seq: bool, - } - - #[derive(Serialize, Deserialize, Debug, PartialEq)] - #[serde(rename_all = "SCREAMING-KEBAB-CASE")] - struct ScreamingKebab { - serialize: bool, - serialize_seq: bool, - } - - assert_tokens( - &E::Serialize { - serialize: true, - serialize_seq: true, - }, - &[ - Token::StructVariant { - name: "E", - variant: "serialize", - len: 2, - }, - Token::Str("serialize"), - Token::Bool(true), - Token::Str("serializeSeq"), - Token::Bool(true), - Token::StructVariantEnd, - ], - ); - - assert_tokens( - &E::SerializeSeq { - serialize: true, - serialize_seq: true, - }, - &[ - Token::StructVariant { - name: "E", - variant: "serialize_seq", - len: 2, - }, - Token::Str("serialize"), - Token::Bool(true), - Token::Str("serialize-seq"), - Token::Bool(true), - Token::StructVariantEnd, - ], - ); - - assert_tokens( - &E::SerializeMap { - serialize: true, - serialize_seq: true, - }, + assert_tokens( + &E::V4 { a_field: true }, &[ Token::StructVariant { name: "E", - variant: "serialize_map", - len: 2, + variant: "V4", + len: 1, }, - Token::Str("SERIALIZE"), - Token::Bool(true), - Token::Str("SERIALIZE_SEQ"), + Token::Str("a_field"), Token::Bool(true), Token::StructVariantEnd, ], ); - - assert_tokens( - &S { - serialize: true, - serialize_seq: true, - }, - &[ - Token::Struct { name: "S", len: 2 }, - Token::Str("Serialize"), - Token::Bool(true), - Token::Str("SerializeSeq"), - Token::Bool(true), - Token::StructEnd, - ], - ); - - assert_tokens( - &ScreamingKebab { - serialize: true, - serialize_seq: true, - }, - &[ - Token::Struct { - name: "ScreamingKebab", - len: 2, - }, - Token::Str("SERIALIZE"), - Token::Bool(true), - Token::Str("SERIALIZE-SEQ"), - Token::Bool(true), - Token::StructEnd, - ], - ); -} - -#[test] -fn test_untagged_newtype_variant_containing_unit_struct_not_map() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Unit; - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(untagged)] - enum Message { - Unit(Unit), - Map(BTreeMap), - } - - assert_tokens( - &Message::Map(BTreeMap::new()), - &[Token::Map { len: Some(0) }, Token::MapEnd], - ); -} - -#[test] -fn test_internally_tagged_newtype_variant_containing_unit_struct() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Info; - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - #[serde(tag = "topic")] - enum Message { - Info(Info), - } - - assert_tokens( - &Message::Info(Info), - &[ - Token::Map { len: Some(1) }, - Token::Str("topic"), - Token::Str("Info"), - Token::MapEnd, - ], - ); } -#[deny(safe_packed_borrows)] #[test] fn test_packed_struct_can_derive_serialize() { #[derive(Copy, Clone, Serialize)] #[repr(packed, C)] + #[allow(dead_code)] struct PackedC { t: f32, } #[derive(Copy, Clone, Serialize)] #[repr(C, packed)] + #[allow(dead_code)] struct CPacked { t: f32, } #[derive(Copy, Clone, Serialize)] #[repr(C, packed(2))] + #[allow(dead_code)] struct CPacked2 { t: f32, } #[derive(Copy, Clone, Serialize)] #[repr(packed(2), C)] + #[allow(dead_code)] struct Packed2C { t: f32, } diff --git a/test_suite/tests/test_remote.rs b/test_suite/tests/test_remote.rs index a38eaa327..919b3e286 100644 --- a/test_suite/tests/test_remote.rs +++ b/test_suite/tests/test_remote.rs @@ -1,20 +1,23 @@ -#![allow(clippy::redundant_field_names)] +#![allow(clippy::redundant_field_names, dead_code)] -use serde::{Deserialize, Serialize}; +use serde_derive::{Deserialize, Serialize}; mod remote { pub struct Unit; pub struct PrimitivePriv(u8); + #[allow(dead_code)] pub struct PrimitivePub(pub u8); pub struct NewtypePriv(Unit); + #[allow(dead_code)] pub struct NewtypePub(pub Unit); pub struct TuplePriv(u8, Unit); + #[allow(dead_code)] pub struct TuplePub(pub u8, pub Unit); pub struct StructPriv { @@ -22,6 +25,7 @@ mod remote { b: Unit, } + #[allow(dead_code)] pub struct StructPub { pub a: u8, pub b: Unit, @@ -74,9 +78,26 @@ mod remote { &self.b } } + + pub struct StructGeneric { + pub value: T, + } + + impl StructGeneric { + #[allow(dead_code)] + pub fn get_value(&self) -> &T { + &self.value + } + } + + #[allow(dead_code)] + pub enum EnumGeneric { + Variant(T), + } } #[derive(Serialize, Deserialize)] +#[allow(dead_code)] struct Test { #[serde(with = "UnitDef")] unit: remote::Unit, @@ -104,10 +125,20 @@ struct Test { #[serde(with = "StructPubDef")] struct_pub: remote::StructPub, + + #[serde(with = "StructConcrete")] + struct_concrete: remote::StructGeneric, + + #[serde(with = "EnumConcrete")] + enum_concrete: remote::EnumGeneric, + + #[serde(with = "ErrorKindDef")] + io_error_kind: ErrorKind, } #[derive(Serialize, Deserialize)] #[serde(remote = "remote::Unit")] +#[allow(dead_code)] struct UnitDef; #[derive(Serialize, Deserialize)] @@ -116,6 +147,7 @@ struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::PrimitivePub")] +#[allow(dead_code)] struct PrimitivePubDef(u8); #[derive(Serialize, Deserialize)] @@ -124,6 +156,7 @@ struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitD #[derive(Serialize, Deserialize)] #[serde(remote = "remote::NewtypePub")] +#[allow(dead_code)] struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit); #[derive(Serialize, Deserialize)] @@ -135,6 +168,7 @@ struct TuplePrivDef( #[derive(Serialize, Deserialize)] #[serde(remote = "remote::TuplePub")] +#[allow(dead_code)] struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit); #[derive(Serialize, Deserialize)] @@ -150,6 +184,7 @@ struct StructPrivDef { #[derive(Serialize, Deserialize)] #[serde(remote = "remote::StructPub")] +#[allow(dead_code)] struct StructPubDef { a: u8, @@ -157,6 +192,46 @@ struct StructPubDef { b: remote::Unit, } +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructGeneric")] +struct StructGenericWithGetterDef { + #[serde(getter = "remote::StructGeneric::get_value")] + value: T, +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructGeneric")] +#[allow(dead_code)] +struct StructConcrete { + value: u8, +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::EnumGeneric")] +#[allow(dead_code)] +enum EnumConcrete { + Variant(u8), +} + +#[derive(Debug)] +#[allow(dead_code)] +enum ErrorKind { + NotFound, + PermissionDenied, + #[allow(dead_code)] + ConnectionRefused, +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "ErrorKind")] +#[non_exhaustive] +#[allow(dead_code)] +enum ErrorKindDef { + NotFound, + PermissionDenied, + // ... +} + impl From for remote::PrimitivePriv { fn from(def: PrimitivePrivDef) -> Self { remote::PrimitivePriv::new(def.0) @@ -180,3 +255,9 @@ impl From for remote::StructPriv { remote::StructPriv::new(def.a, def.b) } } + +impl From> for remote::StructGeneric { + fn from(def: StructGenericWithGetterDef) -> Self { + remote::StructGeneric { value: def.value } + } +} diff --git a/test_suite/tests/test_roundtrip.rs b/test_suite/tests/test_roundtrip.rs index dcdc9996c..00c21892a 100644 --- a/test_suite/tests/test_roundtrip.rs +++ b/test_suite/tests/test_roundtrip.rs @@ -1,5 +1,4 @@ use serde_test::{assert_tokens, Configure, Token}; - use std::net; #[macro_use] @@ -11,10 +10,12 @@ fn ip_addr_roundtrip() { assert_tokens( &net::IpAddr::from(*b"1234").compact(), &seq![ - Token::NewtypeVariant { name: "IpAddr", variant: "V4" }, - + Token::NewtypeVariant { + name: "IpAddr", + variant: "V4" + }, Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, ], ); @@ -25,14 +26,14 @@ fn socket_addr_roundtrip() { assert_tokens( &net::SocketAddr::from((*b"1234567890123456", 1234)).compact(), &seq![ - Token::NewtypeVariant { name: "SocketAddr", variant: "V6" }, - + Token::NewtypeVariant { + name: "SocketAddr", + variant: "V6" + }, Token::Tuple { len: 2 }, - Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd, ], diff --git a/test_suite/tests/test_self.rs b/test_suite/tests/test_self.rs new file mode 100644 index 000000000..ed71d42de --- /dev/null +++ b/test_suite/tests/test_self.rs @@ -0,0 +1,88 @@ +#![allow(clippy::used_underscore_binding, dead_code)] + +use serde_derive::{Deserialize, Serialize}; + +#[test] +fn test_self() { + pub trait Trait { + type Assoc; + } + + #[derive(Deserialize, Serialize)] + pub struct Generics> + where + Self: Trait, + ::Assoc: Sized, + { + _f: T, + } + + impl> Trait for Generics { + type Assoc = Self; + } + + #[derive(Deserialize, Serialize)] + pub struct Struct { + _f1: Box, + _f2: Box<::Assoc>, + _f4: [(); Self::ASSOC], + _f5: [(); Self::assoc()], + } + + impl Struct { + const ASSOC: usize = 1; + const fn assoc() -> usize { + 0 + } + } + + impl Trait for Struct { + type Assoc = Self; + } + + #[derive(Deserialize, Serialize)] + pub struct Tuple( + Box, + Box<::Assoc>, + [(); Self::ASSOC], + [(); Self::assoc()], + ); + + impl Tuple { + const ASSOC: usize = 1; + const fn assoc() -> usize { + 0 + } + } + + impl Trait for Tuple { + type Assoc = Self; + } + + #[derive(Deserialize, Serialize)] + pub enum Enum { + Struct { + _f1: Box, + _f2: Box<::Assoc>, + _f4: [(); Self::ASSOC], + _f5: [(); Self::assoc()], + }, + Tuple( + Box, + Box<::Assoc>, + [(); Self::ASSOC], + [(); Self::assoc()], + ), + } + + impl Enum { + const ASSOC: usize = 1; + const fn assoc() -> usize { + 0 + } + } + + impl Trait for Enum { + type Assoc = Self; + } +} diff --git a/test_suite/tests/test_ser.rs b/test_suite/tests/test_ser.rs index a62569af2..1c8063184 100644 --- a/test_suite/tests/test_ser.rs +++ b/test_suite/tests/test_ser.rs @@ -1,30 +1,26 @@ -#![allow(clippy::unreadable_literal)] +#![allow(clippy::derive_partial_eq_without_eq, clippy::unreadable_literal)] #![cfg_attr(feature = "unstable", feature(never_type))] +use serde_derive::Serialize; +use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token}; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::ffi::CString; -use std::mem; use std::net; -use std::num::Wrapping; +use std::num::{Saturating, Wrapping}; use std::ops::Bound; use std::path::{Path, PathBuf}; use std::rc::{Rc, Weak as RcWeak}; +#[cfg(unix)] +use std::str; use std::sync::atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8, AtomicUsize, }; -use std::sync::{Arc, Weak as ArcWeak}; -use std::time::{Duration, UNIX_EPOCH}; - -#[cfg(unix)] -use std::str; #[cfg(target_arch = "x86_64")] use std::sync::atomic::{AtomicI64, AtomicU64}; - -use fnv::FnvHasher; -use serde::Serialize; -use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token}; +use std::sync::{Arc, Mutex, RwLock, Weak as ArcWeak}; +use std::time::{Duration, UNIX_EPOCH}; #[macro_use] mod macros; @@ -72,563 +68,780 @@ enum Enum { ////////////////////////////////////////////////////////////////////////// -macro_rules! declare_tests { - ( - $readable:tt - $($name:ident { $($value:expr => $tokens:expr,)+ })+ - ) => { - $( - #[test] - fn $name() { - $( - assert_ser_tokens(&$value.$readable(), $tokens); - )+ - } - )+ - }; - - ($($name:ident { $($value:expr => $tokens:expr,)+ })+) => { - $( - #[test] - fn $name() { - $( - assert_ser_tokens(&$value, $tokens); - )+ - } - )+ - } -} - -declare_tests! { - test_unit { - () => &[Token::Unit], - } - test_bool { - true => &[Token::Bool(true)], - false => &[Token::Bool(false)], - } - test_isizes { - 0i8 => &[Token::I8(0)], - 0i16 => &[Token::I16(0)], - 0i32 => &[Token::I32(0)], - 0i64 => &[Token::I64(0)], - } - test_usizes { - 0u8 => &[Token::U8(0)], - 0u16 => &[Token::U16(0)], - 0u32 => &[Token::U32(0)], - 0u64 => &[Token::U64(0)], - } - test_floats { - 0f32 => &[Token::F32(0.)], - 0f64 => &[Token::F64(0.)], - } - test_char { - 'a' => &[Token::Char('a')], - } - test_str { - "abc" => &[Token::Str("abc")], - "abc".to_owned() => &[Token::Str("abc")], - } - test_option { - None:: => &[Token::None], - Some(1) => &[ - Token::Some, - Token::I32(1), - ], - } - test_result { - Ok::(0) => &[ - Token::NewtypeVariant { name: "Result", variant: "Ok" }, +#[test] +fn test_unit() { + assert_ser_tokens(&(), &[Token::Unit]); +} + +#[test] +fn test_bool() { + assert_ser_tokens(&true, &[Token::Bool(true)]); + assert_ser_tokens(&false, &[Token::Bool(false)]); +} + +#[test] +fn test_isizes() { + assert_ser_tokens(&0i8, &[Token::I8(0)]); + assert_ser_tokens(&0i16, &[Token::I16(0)]); + assert_ser_tokens(&0i32, &[Token::I32(0)]); + assert_ser_tokens(&0i64, &[Token::I64(0)]); +} + +#[test] +fn test_usizes() { + assert_ser_tokens(&0u8, &[Token::U8(0)]); + assert_ser_tokens(&0u16, &[Token::U16(0)]); + assert_ser_tokens(&0u32, &[Token::U32(0)]); + assert_ser_tokens(&0u64, &[Token::U64(0)]); +} + +#[test] +fn test_floats() { + assert_ser_tokens(&0f32, &[Token::F32(0.)]); + assert_ser_tokens(&0f64, &[Token::F64(0.)]); +} + +#[test] +fn test_char() { + assert_ser_tokens(&'a', &[Token::Char('a')]); +} + +#[test] +fn test_str() { + assert_ser_tokens(&"abc", &[Token::Str("abc")]); + assert_ser_tokens(&"abc".to_owned(), &[Token::Str("abc")]); +} + +#[test] +fn test_option() { + assert_ser_tokens(&None::, &[Token::None]); + assert_ser_tokens(&Some(1), &[Token::Some, Token::I32(1)]); +} + +#[test] +fn test_result() { + assert_ser_tokens( + &Ok::(0), + &[ + Token::NewtypeVariant { + name: "Result", + variant: "Ok", + }, Token::I32(0), ], - Err::(1) => &[ - Token::NewtypeVariant { name: "Result", variant: "Err" }, + ); + assert_ser_tokens( + &Err::(1), + &[ + Token::NewtypeVariant { + name: "Result", + variant: "Err", + }, Token::I32(1), ], - } - test_slice { - &[0][..0] => &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ], - &[1, 2, 3][..] => &[ + ); +} + +#[test] +fn test_slice() { + assert_ser_tokens(&[0][..0], &[Token::Seq { len: Some(0) }, Token::SeqEnd]); + assert_ser_tokens( + &[1, 2, 3][..], + &[ Token::Seq { len: Some(3) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::SeqEnd, ], - } - test_array { - [0; 0] => &[ - Token::Tuple { len: 0 }, - Token::TupleEnd, - ], - [1, 2, 3] => &[ + ); +} + +#[test] +fn test_array() { + assert_ser_tokens(&[0; 0], &[Token::Tuple { len: 0 }, Token::TupleEnd]); + assert_ser_tokens( + &[1, 2, 3], + &[ Token::Tuple { len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleEnd, ], - } - test_vec { - Vec::::new() => &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ], - vec![vec![], vec![1], vec![2, 3]] => &[ - Token::Seq { len: Some(3) }, - Token::Seq { len: Some(0) }, - Token::SeqEnd, - - Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, + ); +} - Token::Seq { len: Some(2) }, - Token::I32(2), - Token::I32(3), - Token::SeqEnd, - Token::SeqEnd, - ], - } - test_btreeset { - BTreeSet::::new() => &[ +#[test] +fn test_vec() { + assert_ser_tokens( + &Vec::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + assert_ser_tokens( + &vec![vec![], vec![1], vec![2, 3]], + &[ + Token::Seq { len: Some(3) }, Token::Seq { len: Some(0) }, Token::SeqEnd, - ], - btreeset![1] => &[ Token::Seq { len: Some(1) }, - Token::I32(1), - Token::SeqEnd, - ], - } - test_hashset { - HashSet::::new() => &[ - Token::Seq { len: Some(0) }, + Token::I32(1), Token::SeqEnd, - ], - hashset![1] => &[ - Token::Seq { len: Some(1) }, - Token::I32(1), + Token::Seq { len: Some(2) }, + Token::I32(2), + Token::I32(3), Token::SeqEnd, - ], - hashset![FnvHasher @ 1] => &[ - Token::Seq { len: Some(1) }, - Token::I32(1), Token::SeqEnd, ], - } - test_tuple { - (1,) => &[ - Token::Tuple { len: 1 }, - Token::I32(1), - Token::TupleEnd, - ], - (1, 2, 3) => &[ + ); +} + +#[test] +fn test_btreeset() { + assert_ser_tokens( + &BTreeSet::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + assert_ser_tokens( + &btreeset![1], + &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], + ); +} + +#[test] +fn test_hashset() { + assert_ser_tokens( + &HashSet::::new(), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + assert_ser_tokens( + &hashset![1], + &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], + ); + assert_ser_tokens( + &hashset![foldhash::fast::FixedState; 1], + &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], + ); +} + +#[test] +fn test_tuple() { + assert_ser_tokens( + &(1,), + &[Token::Tuple { len: 1 }, Token::I32(1), Token::TupleEnd], + ); + assert_ser_tokens( + &(1, 2, 3), + &[ Token::Tuple { len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleEnd, ], - } - test_btreemap { - btreemap![1 => 2] => &[ + ); +} + +#[test] +fn test_btreemap() { + assert_ser_tokens( + &btreemap![1 => 2], + &[ Token::Map { len: Some(1) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::MapEnd, ], - btreemap![1 => 2, 3 => 4] => &[ + ); + assert_ser_tokens( + &btreemap![1 => 2, 3 => 4], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::I32(2), - - Token::I32(3), - Token::I32(4), + Token::I32(1), + Token::I32(2), + Token::I32(3), + Token::I32(4), Token::MapEnd, ], - btreemap![1 => btreemap![], 2 => btreemap![3 => 4, 5 => 6]] => &[ + ); + assert_ser_tokens( + &btreemap![1 => btreemap![], 2 => btreemap![3 => 4, 5 => 6]], + &[ Token::Map { len: Some(2) }, - Token::I32(1), - Token::Map { len: Some(0) }, - Token::MapEnd, - - Token::I32(2), - Token::Map { len: Some(2) }, - Token::I32(3), - Token::I32(4), - - Token::I32(5), - Token::I32(6), - Token::MapEnd, - Token::MapEnd, - ], - } - test_hashmap { - HashMap::::new() => &[ + Token::I32(1), Token::Map { len: Some(0) }, Token::MapEnd, + Token::I32(2), + Token::Map { len: Some(2) }, + Token::I32(3), + Token::I32(4), + Token::I32(5), + Token::I32(6), + Token::MapEnd, + Token::MapEnd, ], - hashmap![1 => 2] => &[ + ); +} + +#[test] +fn test_hashmap() { + assert_ser_tokens( + &HashMap::::new(), + &[Token::Map { len: Some(0) }, Token::MapEnd], + ); + assert_ser_tokens( + &hashmap![1 => 2], + &[ Token::Map { len: Some(1) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::MapEnd, ], - hashmap![FnvHasher @ 1 => 2] => &[ + ); + assert_ser_tokens( + &hashmap![foldhash::fast::FixedState; 1 => 2], + &[ Token::Map { len: Some(1) }, - Token::I32(1), - Token::I32(2), + Token::I32(1), + Token::I32(2), Token::MapEnd, ], - } - test_unit_struct { - UnitStruct => &[Token::UnitStruct { name: "UnitStruct" }], - } - test_tuple_struct { - TupleStruct(1, 2, 3) => &[ - Token::TupleStruct { name: "TupleStruct", len: 3 }, - Token::I32(1), - Token::I32(2), - Token::I32(3), + ); +} + +#[test] +fn test_unit_struct() { + assert_ser_tokens(&UnitStruct, &[Token::UnitStruct { name: "UnitStruct" }]); +} + +#[test] +fn test_tuple_struct() { + assert_ser_tokens( + &TupleStruct(1, 2, 3), + &[ + Token::TupleStruct { + name: "TupleStruct", + len: 3, + }, + Token::I32(1), + Token::I32(2), + Token::I32(3), Token::TupleStructEnd, ], - } - test_struct { - Struct { a: 1, b: 2, c: 3 } => &[ - Token::Struct { name: "Struct", len: 3 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), + ); +} - Token::Str("c"), - Token::I32(3), +#[test] +fn test_struct() { + assert_ser_tokens( + &Struct { a: 1, b: 2, c: 3 }, + &[ + Token::Struct { + name: "Struct", + len: 3, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), + Token::Str("c"), + Token::I32(3), Token::StructEnd, ], - } - test_enum { - Enum::Unit => &[ - Token::UnitVariant { name: "Enum", variant: "Unit" }, - ], - Enum::One(42) => &[ - Token::NewtypeVariant { name: "Enum", variant: "One" }, + ); +} + +#[test] +fn test_enum() { + assert_ser_tokens( + &Enum::Unit, + &[Token::UnitVariant { + name: "Enum", + variant: "Unit", + }], + ); + assert_ser_tokens( + &Enum::One(42), + &[ + Token::NewtypeVariant { + name: "Enum", + variant: "One", + }, Token::I32(42), ], - Enum::Seq(1, 2) => &[ - Token::TupleVariant { name: "Enum", variant: "Seq", len: 2 }, - Token::I32(1), - Token::I32(2), + ); + assert_ser_tokens( + &Enum::Seq(1, 2), + &[ + Token::TupleVariant { + name: "Enum", + variant: "Seq", + len: 2, + }, + Token::I32(1), + Token::I32(2), Token::TupleVariantEnd, ], - Enum::Map { a: 1, b: 2 } => &[ - Token::StructVariant { name: "Enum", variant: "Map", len: 2 }, - Token::Str("a"), - Token::I32(1), - - Token::Str("b"), - Token::I32(2), + ); + assert_ser_tokens( + &Enum::Map { a: 1, b: 2 }, + &[ + Token::StructVariant { + name: "Enum", + variant: "Map", + len: 2, + }, + Token::Str("a"), + Token::I32(1), + Token::Str("b"), + Token::I32(2), Token::StructVariantEnd, ], - Enum::OneWithSkipped(NotSerializable) => &[ - Token::UnitVariant { name: "Enum", variant: "OneWithSkipped" }, - ], - } - test_box { - Box::new(0i32) => &[Token::I32(0)], - } - test_boxed_slice { - Box::new([0, 1, 2]) => &[ + ); + assert_ser_tokens( + &Enum::OneWithSkipped(NotSerializable), + &[Token::UnitVariant { + name: "Enum", + variant: "OneWithSkipped", + }], + ); +} + +#[test] +fn test_box() { + assert_ser_tokens(&Box::new(0i32), &[Token::I32(0)]); +} + +#[test] +fn test_boxed_slice() { + assert_ser_tokens( + &Box::new([0, 1, 2]), + &[ Token::Tuple { len: 3 }, Token::I32(0), Token::I32(1), Token::I32(2), Token::TupleEnd, ], - } - test_duration { - Duration::new(1, 2) => &[ - Token::Struct { name: "Duration", len: 2 }, - Token::Str("secs"), - Token::U64(1), + ); +} - Token::Str("nanos"), - Token::U32(2), +#[test] +fn test_duration() { + assert_ser_tokens( + &Duration::new(1, 2), + &[ + Token::Struct { + name: "Duration", + len: 2, + }, + Token::Str("secs"), + Token::U64(1), + Token::Str("nanos"), + Token::U32(2), Token::StructEnd, ], - } - test_system_time { - UNIX_EPOCH + Duration::new(1, 200) => &[ - Token::Struct { name: "SystemTime", len: 2 }, - Token::Str("secs_since_epoch"), - Token::U64(1), + ); +} - Token::Str("nanos_since_epoch"), - Token::U32(200), +#[test] +fn test_system_time() { + let system_time = UNIX_EPOCH + Duration::new(1, 200); + assert_ser_tokens( + &system_time, + &[ + Token::Struct { + name: "SystemTime", + len: 2, + }, + Token::Str("secs_since_epoch"), + Token::U64(1), + Token::Str("nanos_since_epoch"), + Token::U32(200), Token::StructEnd, ], - } - test_range { - 1u32..2u32 => &[ - Token::Struct { name: "Range", len: 2 }, - Token::Str("start"), - Token::U32(1), + ); +} - Token::Str("end"), - Token::U32(2), +#[test] +fn test_range() { + assert_ser_tokens( + &(1u32..2u32), + &[ + Token::Struct { + name: "Range", + len: 2, + }, + Token::Str("start"), + Token::U32(1), + Token::Str("end"), + Token::U32(2), Token::StructEnd, ], - } - test_range_inclusive { - 1u32..=2u32 => &[ - Token::Struct { name: "RangeInclusive", len: 2 }, - Token::Str("start"), - Token::U32(1), + ); +} - Token::Str("end"), - Token::U32(2), +#[test] +fn test_range_inclusive() { + assert_ser_tokens( + &(1u32..=2u32), + &[ + Token::Struct { + name: "RangeInclusive", + len: 2, + }, + Token::Str("start"), + Token::U32(1), + Token::Str("end"), + Token::U32(2), + Token::StructEnd, + ], + ); +} + +#[test] +fn test_range_from() { + assert_ser_tokens( + &(1u32..), + &[ + Token::Struct { + name: "RangeFrom", + len: 1, + }, + Token::Str("start"), + Token::U32(1), + Token::StructEnd, + ], + ); +} + +#[test] +fn test_range_to() { + assert_ser_tokens( + &(..2u32), + &[ + Token::Struct { + name: "RangeTo", + len: 1, + }, + Token::Str("end"), + Token::U32(2), Token::StructEnd, ], - } - test_bound { - Bound::Unbounded::<()> => &[ + ); +} + +#[test] +fn test_bound() { + assert_ser_tokens( + &Bound::Unbounded::<()>, + &[ Token::Enum { name: "Bound" }, Token::Str("Unbounded"), Token::Unit, ], - Bound::Included(0u8) => &[ + ); + assert_ser_tokens( + &Bound::Included(0u8), + &[ Token::Enum { name: "Bound" }, Token::Str("Included"), Token::U8(0), ], - Bound::Excluded(0u8) => &[ + ); + assert_ser_tokens( + &Bound::Excluded(0u8), + &[ Token::Enum { name: "Bound" }, Token::Str("Excluded"), Token::U8(0), ], - } - test_path { - Path::new("/usr/local/lib") => &[ - Token::Str("/usr/local/lib"), - ], - } - test_path_buf { - PathBuf::from("/usr/local/lib") => &[ - Token::Str("/usr/local/lib"), - ], - } - test_cstring { - CString::new("abc").unwrap() => &[ - Token::Bytes(b"abc"), - ], - } - test_cstr { - (&*CString::new("abc").unwrap()) => &[ - Token::Bytes(b"abc"), - ], - } - test_rc { - Rc::new(true) => &[ - Token::Bool(true), - ], - } - test_rc_weak_some { - { - let rc = Rc::new(true); - mem::forget(rc.clone()); - Rc::downgrade(&rc) - } => &[ - Token::Some, - Token::Bool(true), - ], - } - test_rc_weak_none { - RcWeak::::new() => &[ - Token::None, - ], - } - test_arc { - Arc::new(true) => &[ - Token::Bool(true), - ], - } - test_arc_weak_some { - { - let arc = Arc::new(true); - mem::forget(arc.clone()); - Arc::downgrade(&arc) - } => &[ - Token::Some, - Token::Bool(true), - ], - } - test_arc_weak_none { - ArcWeak::::new() => &[ - Token::None, - ], - } - test_wrapping { - Wrapping(1usize) => &[ - Token::U64(1), - ], - } - test_rc_dst { - Rc::::from("s") => &[ - Token::Str("s"), - ], - Rc::<[bool]>::from(&[true][..]) => &[ + ); +} + +#[test] +fn test_path() { + assert_ser_tokens( + &Path::new("/usr/local/lib"), + &[Token::Str("/usr/local/lib")], + ); +} + +#[test] +fn test_path_buf() { + assert_ser_tokens( + &PathBuf::from("/usr/local/lib"), + &[Token::Str("/usr/local/lib")], + ); +} + +#[test] +fn test_cstring() { + assert_ser_tokens(&CString::new("abc").unwrap(), &[Token::Bytes(b"abc")]); +} + +#[test] +fn test_cstr() { + let cstring = CString::new("abc").unwrap(); + assert_ser_tokens(cstring.as_c_str(), &[Token::Bytes(b"abc")]); +} + +#[test] +fn test_rc() { + assert_ser_tokens(&Rc::new(true), &[Token::Bool(true)]); +} + +#[test] +fn test_rc_weak_some() { + let rc = Rc::new(true); + assert_ser_tokens(&Rc::downgrade(&rc), &[Token::Some, Token::Bool(true)]); +} + +#[test] +fn test_rc_weak_none() { + assert_ser_tokens(&RcWeak::::new(), &[Token::None]); +} + +#[test] +fn test_arc() { + assert_ser_tokens(&Arc::new(true), &[Token::Bool(true)]); +} + +#[test] +fn test_arc_weak_some() { + let arc = Arc::new(true); + assert_ser_tokens(&Arc::downgrade(&arc), &[Token::Some, Token::Bool(true)]); +} + +#[test] +fn test_arc_weak_none() { + assert_ser_tokens(&ArcWeak::::new(), &[Token::None]); +} + +#[test] +fn test_wrapping() { + assert_ser_tokens(&Wrapping(1usize), &[Token::U64(1)]); +} + +#[test] +fn test_saturating() { + assert_ser_tokens(&Saturating(1usize), &[Token::U64(1)]); +} + +#[test] +fn test_rc_dst() { + assert_ser_tokens(&Rc::::from("s"), &[Token::Str("s")]); + assert_ser_tokens( + &Rc::<[bool]>::from(&[true][..]), + &[ Token::Seq { len: Some(1) }, Token::Bool(true), Token::SeqEnd, ], - } - test_arc_dst { - Arc::::from("s") => &[ - Token::Str("s"), - ], - Arc::<[bool]>::from(&[true][..]) => &[ + ); +} + +#[test] +fn test_arc_dst() { + assert_ser_tokens(&Arc::::from("s"), &[Token::Str("s")]); + assert_ser_tokens( + &Arc::<[bool]>::from(&[true][..]), + &[ Token::Seq { len: Some(1) }, Token::Bool(true), Token::SeqEnd, ], - } - test_fmt_arguments { - format_args!("{}{}", 1, 'a') => &[ - 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)], - } + ); +} + +#[test] +fn test_fmt_arguments() { + assert_ser_tokens(&format_args!("{}{}", 1, 'a'), &[Token::Str("1a")]); +} + +#[test] +fn test_atomic() { + assert_ser_tokens(&AtomicBool::new(false), &[Token::Bool(false)]); + assert_ser_tokens(&AtomicBool::new(true), &[Token::Bool(true)]); + assert_ser_tokens(&AtomicI8::new(63i8), &[Token::I8(63i8)]); + assert_ser_tokens(&AtomicI16::new(-318i16), &[Token::I16(-318i16)]); + assert_ser_tokens(&AtomicI32::new(65792i32), &[Token::I32(65792i32)]); + assert_ser_tokens(&AtomicIsize::new(-65792isize), &[Token::I64(-65792i64)]); + assert_ser_tokens(&AtomicU8::new(192u8), &[Token::U8(192u8)]); + assert_ser_tokens(&AtomicU16::new(510u16), &[Token::U16(510u16)]); + assert_ser_tokens(&AtomicU32::new(131072u32), &[Token::U32(131072u32)]); + assert_ser_tokens(&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! { - readable - - test_net_ipv4addr_readable { - "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], - } - test_net_ipv6addr_readable { - "::1".parse::().unwrap() => &[Token::Str("::1")], - } - test_net_ipaddr_readable { - "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], - } - test_net_socketaddr_readable { - "1.2.3.4:1234".parse::().unwrap() => &[Token::Str("1.2.3.4:1234")], - "1.2.3.4:1234".parse::().unwrap() => &[Token::Str("1.2.3.4:1234")], - "[::1]:1234".parse::().unwrap() => &[Token::Str("[::1]:1234")], - } -} - -declare_tests! { - compact - - test_net_ipv4addr_compact { - net::Ipv4Addr::from(*b"1234") => &seq![ +#[test] +fn test_atomic64() { + assert_ser_tokens( + &AtomicI64::new(-4295032832i64), + &[Token::I64(-4295032832i64)], + ); + assert_ser_tokens( + &AtomicU64::new(12884901888u64), + &[Token::U64(12884901888u64)], + ); +} + +#[test] +fn test_net_ipv4addr_readable() { + assert_ser_tokens( + &"1.2.3.4".parse::().unwrap().readable(), + &[Token::Str("1.2.3.4")], + ); +} + +#[test] +fn test_net_ipv6addr_readable() { + assert_ser_tokens( + &"::1".parse::().unwrap().readable(), + &[Token::Str("::1")], + ); +} + +#[test] +fn test_net_ipaddr_readable() { + assert_ser_tokens( + &"1.2.3.4".parse::().unwrap().readable(), + &[Token::Str("1.2.3.4")], + ); +} + +#[test] +fn test_net_socketaddr_readable() { + assert_ser_tokens( + &"1.2.3.4:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("1.2.3.4:1234")], + ); + assert_ser_tokens( + &"1.2.3.4:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("1.2.3.4:1234")], + ); + assert_ser_tokens( + &"[::1]:1234" + .parse::() + .unwrap() + .readable(), + &[Token::Str("[::1]:1234")], + ); +} + +#[test] +fn test_net_ipv4addr_compact() { + assert_ser_tokens( + &net::Ipv4Addr::from(*b"1234").compact(), + &seq![ Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, ], - } - test_net_ipv6addr_compact { - net::Ipv6Addr::from(*b"1234567890123456") => &seq![ + ); +} + +#[test] +fn test_net_ipv6addr_compact() { + assert_ser_tokens( + &net::Ipv6Addr::from(*b"1234567890123456").compact(), + &seq![ Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, ], - } - test_net_ipaddr_compact { - net::IpAddr::from(*b"1234") => &seq![ - Token::NewtypeVariant { name: "IpAddr", variant: "V4" }, + ); +} +#[test] +fn test_net_ipaddr_compact() { + assert_ser_tokens( + &net::IpAddr::from(*b"1234").compact(), + &seq![ + Token::NewtypeVariant { + name: "IpAddr", + variant: "V4" + }, Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, ], - } - test_net_socketaddr_compact { - net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![ - Token::NewtypeVariant { name: "SocketAddr", variant: "V6" }, + ); +} +#[test] +fn test_net_socketaddr_compact() { + assert_ser_tokens( + &net::SocketAddr::from((*b"1234567890123456", 1234)).compact(), + &seq![ + Token::NewtypeVariant { + name: "SocketAddr", + variant: "V6" + }, Token::Tuple { len: 2 }, - Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd, ], - net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![ + ); + assert_ser_tokens( + &net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234).compact(), + &seq![ Token::Tuple { len: 2 }, - Token::Tuple { len: 4 }, - seq b"1234".iter().map(|&b| Token::U8(b)), + b"1234".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd, ], - net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![ + ); + assert_ser_tokens( + &net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0).compact(), + &seq![ Token::Tuple { len: 2 }, - Token::Tuple { len: 16 }, - seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + b"1234567890123456".iter().copied().map(Token::U8), Token::TupleEnd, - Token::U16(1234), Token::TupleEnd, ], - } + ); } #[cfg(feature = "unstable")] -declare_tests! { - test_never_result { - Ok::(0) => &[ - Token::NewtypeVariant { name: "Result", variant: "Ok" }, +#[test] +fn test_never_result() { + assert_ser_tokens( + &Ok::(0), + &[ + Token::NewtypeVariant { + name: "Result", + variant: "Ok", + }, Token::U8(0), ], - } + ); } #[test] #[cfg(unix)] fn test_cannot_serialize_paths() { - let path = unsafe { str::from_utf8_unchecked(b"Hello \xF0\x90\x80World") }; + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + assert_ser_tokens_error( - &Path::new(path), + &Path::new(OsStr::from_bytes(b"Hello \xF0\x90\x80World")), &[], "path contains invalid UTF-8 characters", ); - - let mut path_buf = PathBuf::new(); - path_buf.push(path); - - assert_ser_tokens_error(&path_buf, &[], "path contains invalid UTF-8 characters"); } #[test] @@ -662,10 +875,45 @@ fn test_enum_skipped() { ); } -#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] #[test] fn test_integer128() { assert_ser_tokens_error(&1i128, &[], "i128 is not supported"); assert_ser_tokens_error(&1u128, &[], "u128 is not supported"); } + +#[test] +fn test_refcell_dst() { + assert_ser_tokens( + &RefCell::new([true]) as &RefCell<[bool]>, + &[ + Token::Seq { len: Some(1) }, + Token::Bool(true), + Token::SeqEnd, + ], + ); +} + +#[test] +fn test_mutex_dst() { + assert_ser_tokens( + &Mutex::new([true]) as &Mutex<[bool]>, + &[ + Token::Seq { len: Some(1) }, + Token::Bool(true), + Token::SeqEnd, + ], + ); +} + +#[test] +fn test_rwlock_dst() { + assert_ser_tokens( + &RwLock::new([true]) as &RwLock<[bool]>, + &[ + Token::Seq { len: Some(1) }, + Token::Bool(true), + Token::SeqEnd, + ], + ); +} diff --git a/test_suite/tests/test_serde_path.rs b/test_suite/tests/test_serde_path.rs index 68971619c..8b04ab437 100644 --- a/test_suite/tests/test_serde_path.rs +++ b/test_suite/tests/test_serde_path.rs @@ -1,6 +1,13 @@ +#![allow( + clippy::elidable_lifetime_names, + clippy::extra_unused_type_parameters, + clippy::needless_lifetimes, + clippy::type_repetition_in_bounds +)] + #[test] fn test_gen_custom_serde() { - #[derive(serde::Serialize, serde::Deserialize)] + #[derive(serde_derive::Serialize, serde_derive::Deserialize)] #[serde(crate = "fake_serde")] struct Foo; @@ -22,19 +29,21 @@ mod fake_serde { { } + #[allow(dead_code)] pub trait Serialize { fn serialize(&self, serializer: S) -> Result; } + #[allow(dead_code)] pub trait Deserialize<'a>: Sized { fn deserialize>(deserializer: D) -> Result; } } -trait AssertNotSerdeSerialize {} +pub trait AssertNotSerdeSerialize {} impl AssertNotSerdeSerialize for T {} -trait AssertNotSerdeDeserialize<'a> {} +pub trait AssertNotSerdeDeserialize<'a> {} impl<'a, T: serde::Deserialize<'a>> AssertNotSerdeDeserialize<'a> for T {} diff --git a/test_suite/tests/test_unstable.rs b/test_suite/tests/test_unstable.rs index f650512d7..0f4cfa599 100644 --- a/test_suite/tests/test_unstable.rs +++ b/test_suite/tests/test_unstable.rs @@ -1,4 +1,5 @@ #![deny(warnings)] +#![allow(clippy::derive_partial_eq_without_eq)] // This test target is convoluted with the actual #[test] in a separate file to // get it so that the stable compiler does not need to parse the code of the diff --git a/test_suite/tests/test_value.rs b/test_suite/tests/test_value.rs index 0bb169df4..3a1922c0f 100644 --- a/test_suite/tests/test_value.rs +++ b/test_suite/tests/test_value.rs @@ -1,6 +1,8 @@ +#![allow(clippy::derive_partial_eq_without_eq, clippy::similar_names)] + use serde::de::value::{self, MapAccessDeserializer}; -use serde::de::{IntoDeserializer, MapAccess, Visitor}; -use serde::{Deserialize, Deserializer}; +use serde::de::{Deserialize, Deserializer, IntoDeserializer, MapAccess, Visitor}; +use serde_derive::Deserialize; use serde_test::{assert_de_tokens, Token}; use std::fmt; @@ -17,7 +19,6 @@ fn test_u32_to_enum() { assert_eq!(E::B, e); } -#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] #[test] fn test_integer128() { let de_u128 = IntoDeserializer::::into_deserializer(1u128); @@ -62,7 +63,7 @@ fn test_map_access_to_enum() { type Value = Potential; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a map") + formatter.write_str("a map") } fn visit_map(self, map: A) -> Result diff --git a/test_suite/tests/ui/borrow/bad_lifetimes.stderr b/test_suite/tests/ui/borrow/bad_lifetimes.stderr index 5b2984977..1a76f67fe 100644 --- a/test_suite/tests/ui/borrow/bad_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/bad_lifetimes.stderr @@ -1,5 +1,5 @@ error: failed to parse borrowed lifetimes: "zzz" - --> $DIR/bad_lifetimes.rs:5:22 + --> tests/ui/borrow/bad_lifetimes.rs:5:22 | 5 | #[serde(borrow = "zzz")] | ^^^^^ diff --git a/test_suite/tests/ui/borrow/duplicate_lifetime.stderr b/test_suite/tests/ui/borrow/duplicate_lifetime.stderr index f9916fd02..b2409c759 100644 --- a/test_suite/tests/ui/borrow/duplicate_lifetime.stderr +++ b/test_suite/tests/ui/borrow/duplicate_lifetime.stderr @@ -1,5 +1,5 @@ error: duplicate borrowed lifetime `'a` - --> $DIR/duplicate_lifetime.rs:5:22 + --> tests/ui/borrow/duplicate_lifetime.rs:5:22 | 5 | #[serde(borrow = "'a + 'a")] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/borrow/duplicate_variant.stderr b/test_suite/tests/ui/borrow/duplicate_variant.stderr index bae8e5fde..cd0746c2c 100644 --- a/test_suite/tests/ui/borrow/duplicate_variant.stderr +++ b/test_suite/tests/ui/borrow/duplicate_variant.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `borrow` - --> $DIR/duplicate_variant.rs:8:13 + --> tests/ui/borrow/duplicate_variant.rs:9:15 | -8 | #[serde(borrow)] - | ^^^^^^ +9 | S(#[serde(borrow)] Str<'a>), + | ^^^^^^ diff --git a/test_suite/tests/ui/borrow/empty_lifetimes.rs b/test_suite/tests/ui/borrow/empty_lifetimes.rs index 8aab744ae..71d17214e 100644 --- a/test_suite/tests/ui/borrow/empty_lifetimes.rs +++ b/test_suite/tests/ui/borrow/empty_lifetimes.rs @@ -3,6 +3,8 @@ use serde_derive::Deserialize; #[derive(Deserialize)] struct Test<'a> { #[serde(borrow = "")] + r: &'a str, + #[serde(borrow = " ")] s: &'a str, } diff --git a/test_suite/tests/ui/borrow/empty_lifetimes.stderr b/test_suite/tests/ui/borrow/empty_lifetimes.stderr index 2d6f042cd..6f1f5c639 100644 --- a/test_suite/tests/ui/borrow/empty_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/empty_lifetimes.stderr @@ -1,5 +1,11 @@ error: at least one lifetime must be borrowed - --> $DIR/empty_lifetimes.rs:5:22 + --> tests/ui/borrow/empty_lifetimes.rs:5:22 | 5 | #[serde(borrow = "")] | ^^ + +error: at least one lifetime must be borrowed + --> tests/ui/borrow/empty_lifetimes.rs:7:22 + | +7 | #[serde(borrow = " ")] + | ^^^^ diff --git a/test_suite/tests/ui/borrow/no_lifetimes.stderr b/test_suite/tests/ui/borrow/no_lifetimes.stderr index 52601e975..dc57b4f9e 100644 --- a/test_suite/tests/ui/borrow/no_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/no_lifetimes.stderr @@ -1,5 +1,5 @@ error: field `s` has no lifetimes to borrow - --> $DIR/no_lifetimes.rs:5:5 + --> tests/ui/borrow/no_lifetimes.rs:5:5 | 5 | / #[serde(borrow)] 6 | | s: String, diff --git a/test_suite/tests/ui/borrow/struct_variant.stderr b/test_suite/tests/ui/borrow/struct_variant.stderr index 5624d2077..4716a6984 100644 --- a/test_suite/tests/ui/borrow/struct_variant.stderr +++ b/test_suite/tests/ui/borrow/struct_variant.stderr @@ -1,5 +1,5 @@ error: #[serde(borrow)] may only be used on newtype variants - --> $DIR/struct_variant.rs:8:5 + --> tests/ui/borrow/struct_variant.rs:8:5 | 8 | / #[serde(borrow)] 9 | | S { s: Str<'a> }, diff --git a/test_suite/tests/ui/borrow/wrong_lifetime.stderr b/test_suite/tests/ui/borrow/wrong_lifetime.stderr index f282e124e..b266201b0 100644 --- a/test_suite/tests/ui/borrow/wrong_lifetime.stderr +++ b/test_suite/tests/ui/borrow/wrong_lifetime.stderr @@ -1,5 +1,5 @@ error: field `s` does not have lifetime 'b - --> $DIR/wrong_lifetime.rs:5:5 + --> tests/ui/borrow/wrong_lifetime.rs:5:5 | 5 | / #[serde(borrow = "'b")] 6 | | s: &'a str, diff --git a/test_suite/tests/ui/conflict/adjacent-tag.stderr b/test_suite/tests/ui/conflict/adjacent-tag.stderr index ad4967958..e49416088 100644 --- a/test_suite/tests/ui/conflict/adjacent-tag.stderr +++ b/test_suite/tests/ui/conflict/adjacent-tag.stderr @@ -1,5 +1,5 @@ error: enum tags `conflict` for type and content conflict with each other - --> $DIR/adjacent-tag.rs:4:1 + --> tests/ui/conflict/adjacent-tag.rs:4:1 | 4 | / #[serde(tag = "conflict", content = "conflict")] 5 | | enum E { diff --git a/test_suite/tests/ui/conflict/alias-enum.rs b/test_suite/tests/ui/conflict/alias-enum.rs new file mode 100644 index 000000000..5ca958b6d --- /dev/null +++ b/test_suite/tests/ui/conflict/alias-enum.rs @@ -0,0 +1,75 @@ +#![allow(non_camel_case_types)] + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +enum E { + S1 { + #[serde(alias = "a", alias = "b", alias = "c")] + a: (), + + // Warning on "c" and "b" + #[serde(alias = "c")] + b: (), + + #[serde(skip_deserializing)] + c: (), + }, + + S2 { + #[serde(alias = "b", alias = "c")] + a: (), + + // Warning on "c" + #[serde(rename = "c")] + b: (), + }, + + #[serde(rename_all = "UPPERCASE")] + S3 { + #[serde(alias = "B", alias = "c")] + a: (), + + // Warning on "b" because this collides with the "B" above after + // applying rename rules + b: (), + }, +} + +#[derive(Deserialize)] +enum E1 { + #[serde(alias = "a", alias = "b", alias = "c")] + a, + + // Warning on "c" and "b" + #[serde(alias = "c")] + b, + + #[serde(skip_deserializing)] + c, +} + +#[derive(Deserialize)] +enum E2 { + #[serde(alias = "b", alias = "c")] + a, + + // Warning on "c" + #[serde(rename = "c")] + b, +} + +#[derive(Deserialize)] +#[serde(rename_all = "UPPERCASE")] +enum E3 { + #[serde(alias = "B", alias = "c")] + a, + + // Warning on "b" because this collides with the "B" above after applying + // rename rules + b, +} + +fn main() { + __FAIL__; +} diff --git a/test_suite/tests/ui/conflict/alias-enum.stderr b/test_suite/tests/ui/conflict/alias-enum.stderr new file mode 100644 index 000000000..b19c04c1a --- /dev/null +++ b/test_suite/tests/ui/conflict/alias-enum.stderr @@ -0,0 +1,79 @@ +error[E0425]: cannot find value `__FAIL__` in this scope + --> tests/ui/conflict/alias-enum.rs:74:5 + | +74 | __FAIL__; + | ^^^^^^^^ not found in this scope + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:13:9 + | + 8 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +13 | b: (), + | ^ no value can reach this + | + = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:12:25 + | + 8 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +12 | #[serde(alias = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:24:26 + | +20 | #[serde(alias = "b", alias = "c")] + | --- matches all the relevant values +... +24 | #[serde(rename = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:35:9 + | +30 | #[serde(alias = "B", alias = "c")] + | --- matches all the relevant values +... +35 | b: (), + | ^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:46:5 + | +41 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +46 | b, + | ^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:45:21 + | +41 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +45 | #[serde(alias = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:58:22 + | +54 | #[serde(alias = "b", alias = "c")] + | --- matches all the relevant values +... +58 | #[serde(rename = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias-enum.rs:70:5 + | +65 | #[serde(alias = "B", alias = "c")] + | --- matches all the relevant values +... +70 | b, + | ^ no value can reach this diff --git a/test_suite/tests/ui/conflict/alias.rs b/test_suite/tests/ui/conflict/alias.rs new file mode 100644 index 000000000..e18254759 --- /dev/null +++ b/test_suite/tests/ui/conflict/alias.rs @@ -0,0 +1,39 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +struct S1 { + #[serde(alias = "a", alias = "b", alias = "c")] + a: (), + + // Warning on "c" and "b" + #[serde(alias = "c")] + b: (), + + #[serde(skip_deserializing)] + c: (), +} + +#[derive(Deserialize)] +struct S2 { + #[serde(alias = "b", alias = "c")] + a: (), + + // Warning on "c" + #[serde(rename = "c")] + b: (), +} + +#[derive(Deserialize)] +#[serde(rename_all = "UPPERCASE")] +struct S3 { + #[serde(alias = "B", alias = "c")] + a: (), + + // Warning on "b" because this collides with the "B" above after applying + // rename rules + b: (), +} + +fn main() { + __FAIL__; +} diff --git a/test_suite/tests/ui/conflict/alias.stderr b/test_suite/tests/ui/conflict/alias.stderr new file mode 100644 index 000000000..cd747facd --- /dev/null +++ b/test_suite/tests/ui/conflict/alias.stderr @@ -0,0 +1,43 @@ +error[E0425]: cannot find value `__FAIL__` in this scope + --> tests/ui/conflict/alias.rs:38:5 + | +38 | __FAIL__; + | ^^^^^^^^ not found in this scope + +warning: unreachable pattern + --> tests/ui/conflict/alias.rs:10:5 + | + 5 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +10 | b: (), + | ^ no value can reach this + | + = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default + +warning: unreachable pattern + --> tests/ui/conflict/alias.rs:9:21 + | +5 | #[serde(alias = "a", alias = "b", alias = "c")] + | --- matches all the relevant values +... +9 | #[serde(alias = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias.rs:22:22 + | +18 | #[serde(alias = "b", alias = "c")] + | --- matches all the relevant values +... +22 | #[serde(rename = "c")] + | ^^^ no value can reach this + +warning: unreachable pattern + --> tests/ui/conflict/alias.rs:34:5 + | +29 | #[serde(alias = "B", alias = "c")] + | --- matches all the relevant values +... +34 | b: (), + | ^ no value can reach this diff --git a/test_suite/tests/ui/conflict/flatten-newtype-struct.rs b/test_suite/tests/ui/conflict/flatten-newtype-struct.rs index 541cbc5db..e37193305 100644 --- a/test_suite/tests/ui/conflict/flatten-newtype-struct.rs +++ b/test_suite/tests/ui/conflict/flatten-newtype-struct.rs @@ -1,5 +1,4 @@ use serde_derive::Serialize; - use std::collections::HashMap; #[derive(Serialize)] diff --git a/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr b/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr index aeacefb9c..852cfb953 100644 --- a/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr +++ b/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr @@ -1,5 +1,5 @@ error: #[serde(flatten)] cannot be used on newtype structs - --> $DIR/flatten-newtype-struct.rs:6:12 + --> tests/ui/conflict/flatten-newtype-struct.rs:5:12 | -6 | struct Foo(#[serde(flatten)] HashMap); +5 | struct Foo(#[serde(flatten)] HashMap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/conflict/flatten-tuple-struct.rs b/test_suite/tests/ui/conflict/flatten-tuple-struct.rs index 5d69060d0..9e1820d33 100644 --- a/test_suite/tests/ui/conflict/flatten-tuple-struct.rs +++ b/test_suite/tests/ui/conflict/flatten-tuple-struct.rs @@ -1,5 +1,4 @@ use serde_derive::Serialize; - use std::collections::HashMap; #[derive(Serialize)] diff --git a/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr b/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr index e1999344c..93c110bd6 100644 --- a/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr +++ b/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr @@ -1,5 +1,5 @@ error: #[serde(flatten)] cannot be used on tuple structs - --> $DIR/flatten-tuple-struct.rs:6:17 + --> tests/ui/conflict/flatten-tuple-struct.rs:5:17 | -6 | struct Foo(u32, #[serde(flatten)] HashMap); +5 | struct Foo(u32, #[serde(flatten)] HashMap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/conflict/from-try-from.stderr b/test_suite/tests/ui/conflict/from-try-from.stderr index 39dc6ce0d..ceb383986 100644 --- a/test_suite/tests/ui/conflict/from-try-from.stderr +++ b/test_suite/tests/ui/conflict/from-try-from.stderr @@ -1,5 +1,5 @@ error: #[serde(from = "...")] and #[serde(try_from = "...")] conflict with each other - --> $DIR/from-try-from.rs:4:1 + --> tests/ui/conflict/from-try-from.rs:4:1 | 4 | / #[serde(from = "u64", try_from = "u64")] 5 | | struct S { diff --git a/test_suite/tests/ui/conflict/internal-tag-alias.stderr b/test_suite/tests/ui/conflict/internal-tag-alias.stderr index 7a57f427c..8afa6a9b7 100644 --- a/test_suite/tests/ui/conflict/internal-tag-alias.stderr +++ b/test_suite/tests/ui/conflict/internal-tag-alias.stderr @@ -1,11 +1,11 @@ error: variant field name `conflict` conflicts with internal tag - --> $DIR/internal-tag-alias.rs:4:1 + --> tests/ui/conflict/internal-tag-alias.rs:4:1 | -4 | / #[serde(tag = "conflict")] -5 | | enum E { -6 | | A { -7 | | #[serde(alias = "conflict")] -8 | | x: (), -9 | | }, + 4 | / #[serde(tag = "conflict")] + 5 | | enum E { + 6 | | A { + 7 | | #[serde(alias = "conflict")] + 8 | | x: (), + 9 | | }, 10 | | } | |_^ diff --git a/test_suite/tests/ui/conflict/internal-tag.stderr b/test_suite/tests/ui/conflict/internal-tag.stderr index f1ae4579a..97f4bc90b 100644 --- a/test_suite/tests/ui/conflict/internal-tag.stderr +++ b/test_suite/tests/ui/conflict/internal-tag.stderr @@ -1,11 +1,11 @@ error: variant field name `conflict` conflicts with internal tag - --> $DIR/internal-tag.rs:4:1 + --> tests/ui/conflict/internal-tag.rs:4:1 | -4 | / #[serde(tag = "conflict")] -5 | | enum E { -6 | | A { -7 | | #[serde(rename = "conflict")] -8 | | x: (), -9 | | }, + 4 | / #[serde(tag = "conflict")] + 5 | | enum E { + 6 | | A { + 7 | | #[serde(rename = "conflict")] + 8 | | x: (), + 9 | | }, 10 | | } | |_^ diff --git a/test_suite/tests/ui/default-attribute/enum.stderr b/test_suite/tests/ui/default-attribute/enum.stderr index a3b7a0277..27fbc1466 100644 --- a/test_suite/tests/ui/default-attribute/enum.stderr +++ b/test_suite/tests/ui/default-attribute/enum.stderr @@ -1,5 +1,5 @@ -error: #[serde(default)] can only be used on structs with named fields - --> $DIR/enum.rs:5:1 +error: #[serde(default)] can only be used on structs + --> tests/ui/default-attribute/enum.rs:4:9 | -5 | enum E { - | ^^^^ +4 | #[serde(default)] + | ^^^^^^^ diff --git a/test_suite/tests/ui/default-attribute/enum_path.stderr b/test_suite/tests/ui/default-attribute/enum_path.stderr index c6523c9ec..65ef3ac43 100644 --- a/test_suite/tests/ui/default-attribute/enum_path.stderr +++ b/test_suite/tests/ui/default-attribute/enum_path.stderr @@ -1,5 +1,5 @@ -error: #[serde(default = "...")] can only be used on structs with named fields - --> $DIR/enum_path.rs:5:1 +error: #[serde(default = "...")] can only be used on structs + --> tests/ui/default-attribute/enum_path.rs:4:9 | -5 | enum E { - | ^^^^ +4 | #[serde(default = "default_e")] + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs new file mode 100644 index 000000000..2e0fc8675 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs @@ -0,0 +1,20 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(tag = "tag", content = "content")] +enum Enum { + // Newtype variants do not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple(u8, #[serde(default = "main")] i8), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr new file mode 100644 index 000000000..50c0ae97b --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:10:33 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +10 | Tuple(u8, #[serde(default = "main")] i8), + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:12:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +12 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:15:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +15 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs new file mode 100644 index 000000000..7c92b15f1 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs @@ -0,0 +1,19 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +enum Enum { + // Newtype variants do not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple(u8, #[serde(default = "main")] i8), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr new file mode 100644 index 000000000..125b7262d --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:9:33 + | +5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +9 | Tuple(u8, #[serde(default = "main")] i8), + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:11:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +11 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:14:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +14 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs new file mode 100644 index 000000000..5e1a4e848 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs @@ -0,0 +1,20 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(tag = "tag")] +enum Enum { + // Newtype variants do not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + // Tuple variants are not supported in internally tagged enums + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr new file mode 100644 index 000000000..fed3e06a4 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr @@ -0,0 +1,23 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:12:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +12 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:15:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +15 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs new file mode 100644 index 000000000..1c5e910d7 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs @@ -0,0 +1,20 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(untagged)] +enum Enum { + // Newtype variants do not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple(u8, #[serde(default = "main")] i8), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr new file mode 100644 index 000000000..027b665d6 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:10:33 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +10 | Tuple(u8, #[serde(default = "main")] i8), + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:12:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +12 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:15:27 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +15 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs new file mode 100644 index 000000000..84b60942d --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs @@ -0,0 +1,9 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Newtype(#[serde(default = "main")] u8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr new file mode 100644 index 000000000..04bb8349d --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Newtype`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:7:34 + | +5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +6 | #[serde(default = "main")] +7 | struct Newtype(#[serde(default = "main")] u8); + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Newtype`, found `()` +7 | struct Newtype(#[serde(default = "main")] u8); + | ------- expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:7:34 + | +5 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +6 | #[serde(default = "main")] +7 | struct Newtype(#[serde(default = "main")] u8); + | ^^^^^^ expected `u8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs b/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs new file mode 100644 index 000000000..3c5370b8e --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs @@ -0,0 +1,15 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr new file mode 100644 index 000000000..4973c03d2 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Struct`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_struct.rs:8:23 + | +5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +8 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_struct.rs:11:23 + | + 5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +11 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Struct`, found `()` +7 | struct Struct { + | ------ expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:8:23 + | +5 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +... +8 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:11:23 + | + 5 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +... +11 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs new file mode 100644 index 000000000..f40e11651 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs @@ -0,0 +1,9 @@ +// Tests that type error points to the path in attribute + +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Tuple(u8, #[serde(default = "main")] i8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr new file mode 100644 index 000000000..dba33bfb4 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Tuple`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:7:36 + | +5 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +6 | #[serde(default = "main")] +7 | struct Tuple(u8, #[serde(default = "main")] i8); + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:6:19 + | +6 | #[serde(default = "main")] + | ^^^^^^ expected `Tuple`, found `()` +7 | struct Tuple(u8, #[serde(default = "main")] i8); + | ----- expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:7:36 + | +5 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +6 | #[serde(default = "main")] +7 | struct Tuple(u8, #[serde(default = "main")] i8); + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr b/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr deleted file mode 100644 index 3557946a2..000000000 --- a/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: #[serde(default)] can only be used on structs with named fields - --> $DIR/nameless_struct_fields.rs:5:9 - | -5 | struct T(u8, u8); - | ^^^^^^^^ diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr b/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr deleted file mode 100644 index db5fa4b8d..000000000 --- a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: #[serde(default = "...")] can only be used on structs with named fields - --> $DIR/nameless_struct_fields_path.rs:5:9 - | -5 | struct T(u8, u8); - | ^^^^^^^^ diff --git a/test_suite/tests/ui/default-attribute/tuple_struct.rs b/test_suite/tests/ui/default-attribute/tuple_struct.rs new file mode 100644 index 000000000..de08a34a5 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/tuple_struct.rs @@ -0,0 +1,47 @@ +use serde_derive::Deserialize; + +// No errors expected. +#[derive(Deserialize)] +struct T0(u8, u8); + +// No errors expected: +// - If both fields are provided, both get value from data. +// - If only one field is provided, the second gets default value. +#[derive(Deserialize)] +struct T1(u8, #[serde(default)] u8); + +// ERROR: The first field can get default value only if sequence is empty, but +// that means that all other fields cannot be deserialized without errors. +#[derive(Deserialize)] +struct T2(#[serde(default)] u8, u8, u8); + +// No errors expected: +// - If both fields are provided, both get value from data. +// - If only one field is provided, the second gets default value. +// - If no fields are provided, both get default value. +#[derive(Deserialize)] +struct T3(#[serde(default)] u8, #[serde(default)] u8); + +//////////////////////////////////////////////////////////////////////////////// + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T4(u8, u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T5(#[serde(default)] u8, u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T6(u8, #[serde(default)] u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T7(#[serde(default)] u8, #[serde(default)] u8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/tuple_struct.stderr b/test_suite/tests/ui/default-attribute/tuple_struct.stderr new file mode 100644 index 000000000..7af857e68 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/tuple_struct.stderr @@ -0,0 +1,11 @@ +error: field must have #[serde(default)] because previous field 0 has #[serde(default)] + --> tests/ui/default-attribute/tuple_struct.rs:16:33 + | +16 | struct T2(#[serde(default)] u8, u8, u8); + | ^^ + +error: field must have #[serde(default)] because previous field 0 has #[serde(default)] + --> tests/ui/default-attribute/tuple_struct.rs:16:37 + | +16 | struct T2(#[serde(default)] u8, u8, u8); + | ^^ diff --git a/test_suite/tests/ui/default-attribute/tuple_struct_path.rs b/test_suite/tests/ui/default-attribute/tuple_struct_path.rs new file mode 100644 index 000000000..7629970cd --- /dev/null +++ b/test_suite/tests/ui/default-attribute/tuple_struct_path.rs @@ -0,0 +1,76 @@ +use serde_derive::Deserialize; + +fn d() -> T { + unimplemented!() +} + +// No errors expected: +// - If both fields are provided, both get value from data. +// - If only one field is provided, the second gets default value. +#[derive(Deserialize)] +struct T1(u8, #[serde(default = "d")] u8); + +// ERROR: The first field can get default value only if sequence is empty, but +// that means that all other fields cannot be deserialized without errors. +#[derive(Deserialize)] +struct T2(#[serde(default = "d")] u8, u8, u8); + +// No errors expected: +// - If both fields are provided, both get value from data. +// - If only one field is provided, the second gets default value. +// - If no fields are provided, both get default value. +#[derive(Deserialize)] +struct T3(#[serde(default = "d")] u8, #[serde(default = "d")] u8); + +//////////////////////////////////////////////////////////////////////////////// + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T1D(#[serde(default = "d")] u8, u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T2D(u8, #[serde(default = "d")] u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize, Default)] +#[serde(default)] +struct T3D(#[serde(default = "d")] u8, #[serde(default = "d")] u8); + +//////////////////////////////////////////////////////////////////////////////// + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T1Path(#[serde(default)] u8, u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T2Path(u8, #[serde(default)] u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T3Path(#[serde(default)] u8, #[serde(default)] u8); + +//////////////////////////////////////////////////////////////////////////////// + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T1PathD(#[serde(default = "d")] u8, u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T2PathD(u8, #[serde(default = "d")] u8); + +// No errors expected -- missing fields get default values. +#[derive(Deserialize)] +#[serde(default = "d")] +struct T3PathD(#[serde(default = "d")] u8, #[serde(default = "d")] u8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/tuple_struct_path.stderr b/test_suite/tests/ui/default-attribute/tuple_struct_path.stderr new file mode 100644 index 000000000..92bf8cf2d --- /dev/null +++ b/test_suite/tests/ui/default-attribute/tuple_struct_path.stderr @@ -0,0 +1,11 @@ +error: field must have #[serde(default)] because previous field 0 has #[serde(default)] + --> tests/ui/default-attribute/tuple_struct_path.rs:16:39 + | +16 | struct T2(#[serde(default = "d")] u8, u8, u8); + | ^^ + +error: field must have #[serde(default)] because previous field 0 has #[serde(default)] + --> tests/ui/default-attribute/tuple_struct_path.rs:16:43 + | +16 | struct T2(#[serde(default = "d")] u8, u8, u8); + | ^^ diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs b/test_suite/tests/ui/default-attribute/union.rs similarity index 57% rename from test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs rename to test_suite/tests/ui/default-attribute/union.rs index f7859ce5a..296512ff0 100644 --- a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs +++ b/test_suite/tests/ui/default-attribute/union.rs @@ -1,7 +1,9 @@ use serde_derive::Deserialize; #[derive(Deserialize)] -#[serde(default = "default_t")] -struct T(u8, u8); +#[serde(default)] +union Union { + f: u8, +} fn main() {} diff --git a/test_suite/tests/ui/default-attribute/union.stderr b/test_suite/tests/ui/default-attribute/union.stderr new file mode 100644 index 000000000..d0268ce34 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union.stderr @@ -0,0 +1,14 @@ +error: #[serde(default)] can only be used on structs + --> tests/ui/default-attribute/union.rs:4:9 + | +4 | #[serde(default)] + | ^^^^^^^ + +error: Serde does not support derive for unions + --> tests/ui/default-attribute/union.rs:4:1 + | +4 | / #[serde(default)] +5 | | union Union { +6 | | f: u8, +7 | | } + | |_^ diff --git a/test_suite/tests/ui/default-attribute/union_path.rs b/test_suite/tests/ui/default-attribute/union_path.rs new file mode 100644 index 000000000..e57f4d1a0 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union_path.rs @@ -0,0 +1,9 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "default_u")] +union Union { + f: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/union_path.stderr b/test_suite/tests/ui/default-attribute/union_path.stderr new file mode 100644 index 000000000..08e89ee18 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union_path.stderr @@ -0,0 +1,14 @@ +error: #[serde(default = "...")] can only be used on structs + --> tests/ui/default-attribute/union_path.rs:4:9 + | +4 | #[serde(default = "default_u")] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: Serde does not support derive for unions + --> tests/ui/default-attribute/union_path.rs:4:1 + | +4 | / #[serde(default = "default_u")] +5 | | union Union { +6 | | f: u8, +7 | | } + | |_^ diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields.rs b/test_suite/tests/ui/default-attribute/unit.rs similarity index 82% rename from test_suite/tests/ui/default-attribute/nameless_struct_fields.rs rename to test_suite/tests/ui/default-attribute/unit.rs index fe21e0d4f..c0500545f 100644 --- a/test_suite/tests/ui/default-attribute/nameless_struct_fields.rs +++ b/test_suite/tests/ui/default-attribute/unit.rs @@ -2,6 +2,6 @@ use serde_derive::Deserialize; #[derive(Deserialize)] #[serde(default)] -struct T(u8, u8); +struct Unit; fn main() {} diff --git a/test_suite/tests/ui/default-attribute/unit.stderr b/test_suite/tests/ui/default-attribute/unit.stderr new file mode 100644 index 000000000..c99c3bb17 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit.stderr @@ -0,0 +1,7 @@ +error: #[serde(default)] can only be used on structs that have fields + --> tests/ui/default-attribute/unit.rs:3:10 + | +3 | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/test_suite/tests/ui/default-attribute/unit_path.rs b/test_suite/tests/ui/default-attribute/unit_path.rs new file mode 100644 index 000000000..25705fad5 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit_path.rs @@ -0,0 +1,7 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "default_u")] +struct Unit; + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/unit_path.stderr b/test_suite/tests/ui/default-attribute/unit_path.stderr new file mode 100644 index 000000000..430136120 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit_path.stderr @@ -0,0 +1,5 @@ +error: #[serde(default = "...")] can only be used on structs that have fields + --> tests/ui/default-attribute/unit_path.rs:4:9 + | +4 | #[serde(default = "default_u")] + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/deprecated/deprecated_de_with.rs b/test_suite/tests/ui/deprecated/deprecated_de_with.rs new file mode 100644 index 000000000..83466525f --- /dev/null +++ b/test_suite/tests/ui/deprecated/deprecated_de_with.rs @@ -0,0 +1,20 @@ +#![deny(deprecated)] + +use serde::Deserializer; +use serde_derive::Deserialize; + +#[derive(Deserialize)] +pub struct Struct { + #[serde(deserialize_with = "deprecated_with")] + pub field: i32, +} + +#[deprecated] +fn deprecated_with<'de, D>(_deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + unimplemented!() +} + +fn main() {} diff --git a/test_suite/tests/ui/deprecated/deprecated_de_with.stderr b/test_suite/tests/ui/deprecated/deprecated_de_with.stderr new file mode 100644 index 000000000..6e4ede677 --- /dev/null +++ b/test_suite/tests/ui/deprecated/deprecated_de_with.stderr @@ -0,0 +1,11 @@ +error: use of deprecated function `deprecated_with` + --> tests/ui/deprecated/deprecated_de_with.rs:8:32 + | +8 | #[serde(deserialize_with = "deprecated_with")] + | ^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/deprecated/deprecated_de_with.rs:1:9 + | +1 | #![deny(deprecated)] + | ^^^^^^^^^^ diff --git a/test_suite/tests/ui/deprecated/deprecated_ser_with.rs b/test_suite/tests/ui/deprecated/deprecated_ser_with.rs new file mode 100644 index 000000000..72f55a36d --- /dev/null +++ b/test_suite/tests/ui/deprecated/deprecated_ser_with.rs @@ -0,0 +1,20 @@ +#![deny(deprecated)] + +use serde::Serializer; +use serde_derive::Serialize; + +#[derive(Serialize)] +pub struct Struct { + #[serde(serialize_with = "deprecated_with")] + pub field: i32, +} + +#[deprecated] +fn deprecated_with(_field: &i32, _serializer: S) -> Result +where + S: Serializer, +{ + unimplemented!() +} + +fn main() {} diff --git a/test_suite/tests/ui/deprecated/deprecated_ser_with.stderr b/test_suite/tests/ui/deprecated/deprecated_ser_with.stderr new file mode 100644 index 000000000..574c71168 --- /dev/null +++ b/test_suite/tests/ui/deprecated/deprecated_ser_with.stderr @@ -0,0 +1,11 @@ +error: use of deprecated function `deprecated_with` + --> tests/ui/deprecated/deprecated_ser_with.rs:8:30 + | +8 | #[serde(serialize_with = "deprecated_with")] + | ^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/deprecated/deprecated_ser_with.rs:1:9 + | +1 | #![deny(deprecated)] + | ^^^^^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr index 34ecd735c..2def40dc0 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr @@ -1,5 +1,5 @@ error: unknown serde field attribute `serialize` - --> $DIR/rename-and-ser.rs:5:27 + --> tests/ui/duplicate-attribute/rename-and-ser.rs:5:27 | 5 | #[serde(rename = "x", serialize = "y")] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr index 979f97385..2add149c1 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-rename-ser.rs:5:38 + --> tests/ui/duplicate-attribute/rename-ser-rename-ser.rs:5:38 | 5 | #[serde(rename(serialize = "x"), rename(serialize = "y"))] | ^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr index 866b2372f..276e176bb 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-rename.rs:6:13 + --> tests/ui/duplicate-attribute/rename-ser-rename.rs:6:13 | 6 | #[serde(rename = "y")] | ^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr index e6e3b3843..a689503e9 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-ser.rs:5:37 + --> tests/ui/duplicate-attribute/rename-ser-ser.rs:5:37 | 5 | #[serde(rename(serialize = "x", serialize = "y"))] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr b/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr index 9973b4a87..cc2f9ba5b 100644 --- a/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `rename` - --> $DIR/two-rename-ser.rs:6:13 + --> tests/ui/duplicate-attribute/two-rename-ser.rs:6:13 | 6 | #[serde(rename(serialize = "y"))] | ^^^^^^ diff --git a/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr b/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr index 62e29d574..4770758b1 100644 --- a/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr +++ b/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr @@ -1,5 +1,5 @@ error: duplicate serde attribute `serialize_with` - --> $DIR/with-and-serialize-with.rs:5:25 + --> tests/ui/duplicate-attribute/with-and-serialize-with.rs:5:25 | 5 | #[serde(with = "w", serialize_with = "s")] | ^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/enum-representation/content-no-tag.stderr b/test_suite/tests/ui/enum-representation/content-no-tag.stderr index ea3602816..4d94c446a 100644 --- a/test_suite/tests/ui/enum-representation/content-no-tag.stderr +++ b/test_suite/tests/ui/enum-representation/content-no-tag.stderr @@ -1,5 +1,5 @@ error: #[serde(tag = "...", content = "...")] must be used together - --> $DIR/content-no-tag.rs:4:9 + --> tests/ui/enum-representation/content-no-tag.rs:4:9 | 4 | #[serde(content = "c")] | ^^^^^^^ diff --git a/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr b/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr index cbe2cf851..d49a74db5 100644 --- a/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr +++ b/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr @@ -1,5 +1,5 @@ error: #[serde(tag = "...")] cannot be used with tuple variants - --> $DIR/internal-tuple-variant.rs:6:5 + --> tests/ui/enum-representation/internal-tuple-variant.rs:6:5 | 6 | Tuple(u8, u8), | ^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.rs b/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.rs new file mode 100644 index 000000000..a33398cae --- /dev/null +++ b/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.rs @@ -0,0 +1,10 @@ +use serde_derive::Serialize; + +#[derive(Serialize)] +enum E { + #[serde(untagged)] + A(u8), + B(String), +} + +fn main() {} diff --git a/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.stderr b/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.stderr new file mode 100644 index 000000000..08ee26663 --- /dev/null +++ b/test_suite/tests/ui/enum-representation/partially_tagged_wrong_order.stderr @@ -0,0 +1,5 @@ +error: all variants with the #[serde(untagged)] attribute must be placed at the end of the enum + --> tests/ui/enum-representation/partially_tagged_wrong_order.rs:6:5 + | +6 | A(u8), + | ^ diff --git a/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr index 9f42b51b3..f831b7f23 100644 --- a/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr @@ -1,17 +1,17 @@ error: untagged enum cannot have #[serde(tag = "...", content = "...")] - --> $DIR/untagged-and-adjacent.rs:4:9 + --> tests/ui/enum-representation/untagged-and-adjacent.rs:4:9 | 4 | #[serde(untagged)] | ^^^^^^^^ error: untagged enum cannot have #[serde(tag = "...", content = "...")] - --> $DIR/untagged-and-adjacent.rs:5:9 + --> tests/ui/enum-representation/untagged-and-adjacent.rs:5:9 | 5 | #[serde(tag = "t", content = "c")] | ^^^ error: untagged enum cannot have #[serde(tag = "...", content = "...")] - --> $DIR/untagged-and-adjacent.rs:5:20 + --> tests/ui/enum-representation/untagged-and-adjacent.rs:5:20 | 5 | #[serde(tag = "t", content = "c")] | ^^^^^^^ diff --git a/test_suite/tests/ui/enum-representation/untagged-and-content.stderr b/test_suite/tests/ui/enum-representation/untagged-and-content.stderr index 467d6c27a..492de8baf 100644 --- a/test_suite/tests/ui/enum-representation/untagged-and-content.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-and-content.stderr @@ -1,11 +1,11 @@ error: untagged enum cannot have #[serde(content = "...")] - --> $DIR/untagged-and-content.rs:4:9 + --> tests/ui/enum-representation/untagged-and-content.rs:4:9 | 4 | #[serde(untagged)] | ^^^^^^^^ error: untagged enum cannot have #[serde(content = "...")] - --> $DIR/untagged-and-content.rs:5:9 + --> tests/ui/enum-representation/untagged-and-content.rs:5:9 | 5 | #[serde(content = "c")] | ^^^^^^^ diff --git a/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr b/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr index 78fed3dab..24508599f 100644 --- a/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr @@ -1,11 +1,11 @@ error: enum cannot be both untagged and internally tagged - --> $DIR/untagged-and-internal.rs:4:9 + --> tests/ui/enum-representation/untagged-and-internal.rs:4:9 | 4 | #[serde(untagged)] | ^^^^^^^^ error: enum cannot be both untagged and internally tagged - --> $DIR/untagged-and-internal.rs:5:9 + --> tests/ui/enum-representation/untagged-and-internal.rs:5:9 | 5 | #[serde(tag = "type")] | ^^^ diff --git a/test_suite/tests/ui/enum-representation/untagged-struct.stderr b/test_suite/tests/ui/enum-representation/untagged-struct.stderr index 8a065d9b0..495a9f4f7 100644 --- a/test_suite/tests/ui/enum-representation/untagged-struct.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-struct.stderr @@ -1,5 +1,5 @@ error: #[serde(untagged)] can only be used on enums - --> $DIR/untagged-struct.rs:5:1 + --> tests/ui/enum-representation/untagged-struct.rs:4:9 | -5 | struct S; - | ^^^^^^ +4 | #[serde(untagged)] + | ^^^^^^^^ diff --git a/test_suite/tests/ui/expected-string/boolean.stderr b/test_suite/tests/ui/expected-string/boolean.stderr index f14bc7e65..f0831a73d 100644 --- a/test_suite/tests/ui/expected-string/boolean.stderr +++ b/test_suite/tests/ui/expected-string/boolean.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/boolean.rs:5:22 + --> tests/ui/expected-string/boolean.rs:5:22 | 5 | #[serde(rename = true)] | ^^^^ diff --git a/test_suite/tests/ui/expected-string/byte_character.stderr b/test_suite/tests/ui/expected-string/byte_character.stderr index 3b801dcb2..af5f82adb 100644 --- a/test_suite/tests/ui/expected-string/byte_character.stderr +++ b/test_suite/tests/ui/expected-string/byte_character.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/byte_character.rs:5:22 + --> tests/ui/expected-string/byte_character.rs:5:22 | 5 | #[serde(rename = b'a')] | ^^^^ diff --git a/test_suite/tests/ui/expected-string/byte_string.stderr b/test_suite/tests/ui/expected-string/byte_string.stderr index a16b0b92a..9be8444b5 100644 --- a/test_suite/tests/ui/expected-string/byte_string.stderr +++ b/test_suite/tests/ui/expected-string/byte_string.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/byte_string.rs:5:22 + --> tests/ui/expected-string/byte_string.rs:5:22 | 5 | #[serde(rename = b"byte string")] | ^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/expected-string/character.stderr b/test_suite/tests/ui/expected-string/character.stderr index 4524c07fa..4a757bc4c 100644 --- a/test_suite/tests/ui/expected-string/character.stderr +++ b/test_suite/tests/ui/expected-string/character.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/character.rs:5:22 + --> tests/ui/expected-string/character.rs:5:22 | 5 | #[serde(rename = 'a')] | ^^^ diff --git a/test_suite/tests/ui/expected-string/float.stderr b/test_suite/tests/ui/expected-string/float.stderr index f8c78c466..eaa72f594 100644 --- a/test_suite/tests/ui/expected-string/float.stderr +++ b/test_suite/tests/ui/expected-string/float.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/float.rs:5:22 + --> tests/ui/expected-string/float.rs:5:22 | 5 | #[serde(rename = 3.14)] | ^^^^ diff --git a/test_suite/tests/ui/expected-string/integer.stderr b/test_suite/tests/ui/expected-string/integer.stderr index 0d26e6087..8b9fae50c 100644 --- a/test_suite/tests/ui/expected-string/integer.stderr +++ b/test_suite/tests/ui/expected-string/integer.stderr @@ -1,5 +1,5 @@ error: expected serde rename attribute to be a string: `rename = "..."` - --> $DIR/integer.rs:5:22 + --> tests/ui/expected-string/integer.rs:5:22 | 5 | #[serde(rename = 100)] | ^^^ diff --git a/test_suite/tests/ui/identifier/both.stderr b/test_suite/tests/ui/identifier/both.stderr index 7cc3e86ea..f14467ab1 100644 --- a/test_suite/tests/ui/identifier/both.stderr +++ b/test_suite/tests/ui/identifier/both.stderr @@ -1,11 +1,11 @@ error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set - --> $DIR/both.rs:4:9 + --> tests/ui/identifier/both.rs:4:9 | 4 | #[serde(field_identifier, variant_identifier)] | ^^^^^^^^^^^^^^^^ error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set - --> $DIR/both.rs:4:27 + --> tests/ui/identifier/both.rs:4:27 | 4 | #[serde(field_identifier, variant_identifier)] | ^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/identifier/field_struct.stderr b/test_suite/tests/ui/identifier/field_struct.stderr index c87dd3bd5..a874cfcda 100644 --- a/test_suite/tests/ui/identifier/field_struct.stderr +++ b/test_suite/tests/ui/identifier/field_struct.stderr @@ -1,5 +1,5 @@ error: #[serde(field_identifier)] can only be used on an enum - --> $DIR/field_struct.rs:5:1 + --> tests/ui/identifier/field_struct.rs:5:1 | 5 | struct S; | ^^^^^^ diff --git a/test_suite/tests/ui/identifier/field_tuple.stderr b/test_suite/tests/ui/identifier/field_tuple.stderr index 5c2465a9d..4d57e925d 100644 --- a/test_suite/tests/ui/identifier/field_tuple.stderr +++ b/test_suite/tests/ui/identifier/field_tuple.stderr @@ -1,5 +1,5 @@ error: #[serde(field_identifier)] may only contain unit variants - --> $DIR/field_tuple.rs:7:5 + --> tests/ui/identifier/field_tuple.rs:7:5 | 7 | B(u8, u8), | ^^^^^^^^^ diff --git a/test_suite/tests/ui/identifier/newtype_not_last.stderr b/test_suite/tests/ui/identifier/newtype_not_last.stderr index d4af4203c..40801b72d 100644 --- a/test_suite/tests/ui/identifier/newtype_not_last.stderr +++ b/test_suite/tests/ui/identifier/newtype_not_last.stderr @@ -1,5 +1,5 @@ error: `Other` must be the last variant - --> $DIR/newtype_not_last.rs:7:5 + --> tests/ui/identifier/newtype_not_last.rs:7:5 | 7 | Other(String), | ^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/identifier/not_unit.stderr b/test_suite/tests/ui/identifier/not_unit.stderr index 612bfc630..06341b13e 100644 --- a/test_suite/tests/ui/identifier/not_unit.stderr +++ b/test_suite/tests/ui/identifier/not_unit.stderr @@ -1,5 +1,5 @@ error: #[serde(other)] must be on a unit variant - --> $DIR/not_unit.rs:7:5 + --> tests/ui/identifier/not_unit.rs:7:5 | 7 | / #[serde(other)] 8 | | Other(u8, u8), diff --git a/test_suite/tests/ui/identifier/other_not_last.stderr b/test_suite/tests/ui/identifier/other_not_last.stderr index 4a0525d67..3228799c1 100644 --- a/test_suite/tests/ui/identifier/other_not_last.stderr +++ b/test_suite/tests/ui/identifier/other_not_last.stderr @@ -1,5 +1,5 @@ error: #[serde(other)] must be on the last variant - --> $DIR/other_not_last.rs:7:5 + --> tests/ui/identifier/other_not_last.rs:7:5 | 7 | / #[serde(other)] 8 | | Other, diff --git a/test_suite/tests/ui/identifier/other_untagged.stderr b/test_suite/tests/ui/identifier/other_untagged.stderr index ddcf7b5a2..6bccdfb9a 100644 --- a/test_suite/tests/ui/identifier/other_untagged.stderr +++ b/test_suite/tests/ui/identifier/other_untagged.stderr @@ -1,5 +1,5 @@ error: #[serde(other)] cannot appear on untagged enum - --> $DIR/other_untagged.rs:6:5 + --> tests/ui/identifier/other_untagged.rs:6:5 | 6 | / #[serde(other)] 7 | | Other, diff --git a/test_suite/tests/ui/identifier/other_variant.stderr b/test_suite/tests/ui/identifier/other_variant.stderr index d9089d7f0..eed5074c7 100644 --- a/test_suite/tests/ui/identifier/other_variant.stderr +++ b/test_suite/tests/ui/identifier/other_variant.stderr @@ -1,5 +1,5 @@ error: #[serde(other)] may not be used on a variant identifier - --> $DIR/other_variant.rs:6:5 + --> tests/ui/identifier/other_variant.rs:6:5 | 6 | / #[serde(other)] 7 | | Other, diff --git a/test_suite/tests/ui/identifier/variant_struct.stderr b/test_suite/tests/ui/identifier/variant_struct.stderr index ba8ed0672..be4f59e02 100644 --- a/test_suite/tests/ui/identifier/variant_struct.stderr +++ b/test_suite/tests/ui/identifier/variant_struct.stderr @@ -1,5 +1,5 @@ error: #[serde(variant_identifier)] can only be used on an enum - --> $DIR/variant_struct.rs:5:1 + --> tests/ui/identifier/variant_struct.rs:5:1 | 5 | struct S; | ^^^^^^ diff --git a/test_suite/tests/ui/identifier/variant_tuple.stderr b/test_suite/tests/ui/identifier/variant_tuple.stderr index 9fb0a7fb3..a602e5234 100644 --- a/test_suite/tests/ui/identifier/variant_tuple.stderr +++ b/test_suite/tests/ui/identifier/variant_tuple.stderr @@ -1,5 +1,5 @@ error: #[serde(variant_identifier)] may only contain unit variants - --> $DIR/variant_tuple.rs:7:5 + --> tests/ui/identifier/variant_tuple.rs:7:5 | 7 | B(u8, u8), | ^^^^^^^^^ diff --git a/test_suite/tests/ui/malformed/bound.stderr b/test_suite/tests/ui/malformed/bound.stderr index 59537de1d..7fe8df979 100644 --- a/test_suite/tests/ui/malformed/bound.stderr +++ b/test_suite/tests/ui/malformed/bound.stderr @@ -1,5 +1,5 @@ error: malformed bound attribute, expected `bound(serialize = ..., deserialize = ...)` - --> $DIR/bound.rs:5:19 + --> tests/ui/malformed/bound.rs:5:19 | 5 | #[serde(bound(unknown))] | ^^^^^^^ diff --git a/test_suite/tests/ui/malformed/cut_off.stderr b/test_suite/tests/ui/malformed/cut_off.stderr index d3945c302..fed0d5557 100644 --- a/test_suite/tests/ui/malformed/cut_off.stderr +++ b/test_suite/tests/ui/malformed/cut_off.stderr @@ -1,5 +1,5 @@ -error: unexpected end of input, expected literal - --> $DIR/cut_off.rs:4:17 +error: unexpected end of input, expected an expression + --> tests/ui/malformed/cut_off.rs:4:17 | 4 | #[serde(rename =)] | ^ diff --git a/test_suite/tests/ui/malformed/not_list.stderr b/test_suite/tests/ui/malformed/not_list.stderr index 31eae65d8..799069a2a 100644 --- a/test_suite/tests/ui/malformed/not_list.stderr +++ b/test_suite/tests/ui/malformed/not_list.stderr @@ -1,11 +1,11 @@ -error: expected #[serde(...)] - --> $DIR/not_list.rs:4:3 +error: expected attribute arguments in parentheses: #[serde(...)] + --> tests/ui/malformed/not_list.rs:4:3 | 4 | #[serde] | ^^^^^ -error: expected #[serde(...)] - --> $DIR/not_list.rs:5:3 +error: expected parentheses: #[serde(...)] + --> tests/ui/malformed/not_list.rs:5:9 | 5 | #[serde = "?"] - | ^^^^^^^^^^^ + | ^ diff --git a/test_suite/tests/ui/malformed/rename.stderr b/test_suite/tests/ui/malformed/rename.stderr index a2e244f56..2f22cca84 100644 --- a/test_suite/tests/ui/malformed/rename.stderr +++ b/test_suite/tests/ui/malformed/rename.stderr @@ -1,5 +1,5 @@ error: malformed rename attribute, expected `rename(serialize = ..., deserialize = ...)` - --> $DIR/rename.rs:5:20 + --> tests/ui/malformed/rename.rs:5:20 | 5 | #[serde(rename(unknown))] | ^^^^^^^ diff --git a/test_suite/tests/ui/malformed/str_suffix.rs b/test_suite/tests/ui/malformed/str_suffix.rs new file mode 100644 index 000000000..20f13dfc5 --- /dev/null +++ b/test_suite/tests/ui/malformed/str_suffix.rs @@ -0,0 +1,10 @@ +use serde_derive::Serialize; + +#[derive(Serialize)] +#[serde(bound = ""huh)] +pub struct Struct { + #[serde(rename = ""what)] + pub field: i32, +} + +fn main() {} diff --git a/test_suite/tests/ui/malformed/str_suffix.stderr b/test_suite/tests/ui/malformed/str_suffix.stderr new file mode 100644 index 000000000..3d4beae65 --- /dev/null +++ b/test_suite/tests/ui/malformed/str_suffix.stderr @@ -0,0 +1,11 @@ +error: unexpected suffix `huh` on string literal + --> tests/ui/malformed/str_suffix.rs:4:17 + | +4 | #[serde(bound = ""huh)] + | ^^^^^ + +error: unexpected suffix `what` on string literal + --> tests/ui/malformed/str_suffix.rs:6:22 + | +6 | #[serde(rename = ""what)] + | ^^^^^^ diff --git a/test_suite/tests/ui/malformed/trailing_expr.rs b/test_suite/tests/ui/malformed/trailing_expr.rs new file mode 100644 index 000000000..f117e0231 --- /dev/null +++ b/test_suite/tests/ui/malformed/trailing_expr.rs @@ -0,0 +1,9 @@ +use serde_derive::Serialize; + +#[derive(Serialize)] +struct S { + #[serde(skip_serializing_if, x.is_empty())] + x: Vec<()>, +} + +fn main() {} diff --git a/test_suite/tests/ui/malformed/trailing_expr.stderr b/test_suite/tests/ui/malformed/trailing_expr.stderr new file mode 100644 index 000000000..539d7a358 --- /dev/null +++ b/test_suite/tests/ui/malformed/trailing_expr.stderr @@ -0,0 +1,5 @@ +error: expected `=` + --> tests/ui/malformed/trailing_expr.rs:5:32 + | +5 | #[serde(skip_serializing_if, x.is_empty())] + | ^ diff --git a/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr b/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr index 642f3f1c8..8145b0623 100644 --- a/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr +++ b/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr @@ -1,5 +1,5 @@ error: cannot deserialize when there is a lifetime parameter called 'de - --> $DIR/deserialize_de_lifetime.rs:4:10 + --> tests/ui/precondition/deserialize_de_lifetime.rs:4:10 | 4 | struct S<'de> { | ^^^ diff --git a/test_suite/tests/ui/precondition/deserialize_dst.stderr b/test_suite/tests/ui/precondition/deserialize_dst.stderr index 923864561..2d0d69fad 100644 --- a/test_suite/tests/ui/precondition/deserialize_dst.stderr +++ b/test_suite/tests/ui/precondition/deserialize_dst.stderr @@ -1,5 +1,5 @@ error: cannot deserialize a dynamically sized struct - --> $DIR/deserialize_dst.rs:4:1 + --> tests/ui/precondition/deserialize_dst.rs:4:1 | 4 | / struct S { 5 | | string: String, diff --git a/test_suite/tests/ui/precondition/serialize_field_identifier.stderr b/test_suite/tests/ui/precondition/serialize_field_identifier.stderr index 9b59f4f84..d0266d772 100644 --- a/test_suite/tests/ui/precondition/serialize_field_identifier.stderr +++ b/test_suite/tests/ui/precondition/serialize_field_identifier.stderr @@ -1,5 +1,5 @@ error: field identifiers cannot be serialized - --> $DIR/serialize_field_identifier.rs:4:1 + --> tests/ui/precondition/serialize_field_identifier.rs:4:1 | 4 | / #[serde(field_identifier)] 5 | | enum F { diff --git a/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr b/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr index 4641f35fd..87e717661 100644 --- a/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr +++ b/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr @@ -1,5 +1,5 @@ error: variant identifiers cannot be serialized - --> $DIR/serialize_variant_identifier.rs:4:1 + --> tests/ui/precondition/serialize_variant_identifier.rs:4:1 | 4 | / #[serde(variant_identifier)] 5 | | enum F { diff --git a/test_suite/tests/ui/remote/bad_getter.stderr b/test_suite/tests/ui/remote/bad_getter.stderr index 871509269..9efb2082d 100644 --- a/test_suite/tests/ui/remote/bad_getter.stderr +++ b/test_suite/tests/ui/remote/bad_getter.stderr @@ -1,5 +1,5 @@ error: failed to parse path: "~~~" - --> $DIR/bad_getter.rs:12:22 + --> tests/ui/remote/bad_getter.rs:12:22 | 12 | #[serde(getter = "~~~")] | ^^^^^ diff --git a/test_suite/tests/ui/remote/bad_remote.stderr b/test_suite/tests/ui/remote/bad_remote.stderr index dc985564c..48ccca1de 100644 --- a/test_suite/tests/ui/remote/bad_remote.stderr +++ b/test_suite/tests/ui/remote/bad_remote.stderr @@ -1,5 +1,5 @@ error: failed to parse path: "~~~" - --> $DIR/bad_remote.rs:10:18 + --> tests/ui/remote/bad_remote.rs:10:18 | 10 | #[serde(remote = "~~~")] | ^^^^^ diff --git a/test_suite/tests/ui/remote/double_generic.rs b/test_suite/tests/ui/remote/double_generic.rs new file mode 100644 index 000000000..0e286a91e --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.rs @@ -0,0 +1,17 @@ +use serde_derive::{Deserialize, Serialize}; + +mod remote { + pub struct Struct { + pub t: T, + pub u: U, + } +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructGeneric")] +struct StructDef { + t: u8, + u: U, +} + +fn main() {} diff --git a/test_suite/tests/ui/remote/double_generic.stderr b/test_suite/tests/ui/remote/double_generic.stderr new file mode 100644 index 000000000..4188b44a2 --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.stderr @@ -0,0 +1,5 @@ +error: remove generic parameters from this path + --> tests/ui/remote/double_generic.rs:11:18 + | +11 | #[serde(remote = "remote::StructGeneric")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/remote/enum_getter.stderr b/test_suite/tests/ui/remote/enum_getter.stderr index 77edefc57..a3c0deac9 100644 --- a/test_suite/tests/ui/remote/enum_getter.stderr +++ b/test_suite/tests/ui/remote/enum_getter.stderr @@ -1,5 +1,5 @@ error: #[serde(getter = "...")] is not allowed in an enum - --> $DIR/enum_getter.rs:10:1 + --> tests/ui/remote/enum_getter.rs:10:1 | 10 | / #[serde(remote = "remote::E")] 11 | | pub enum E { diff --git a/test_suite/tests/ui/remote/missing_field.rs b/test_suite/tests/ui/remote/missing_field.rs index e3f3ec8fb..916569348 100644 --- a/test_suite/tests/ui/remote/missing_field.rs +++ b/test_suite/tests/ui/remote/missing_field.rs @@ -1,4 +1,4 @@ -use serde_derive::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; mod remote { pub struct S { diff --git a/test_suite/tests/ui/remote/missing_field.stderr b/test_suite/tests/ui/remote/missing_field.stderr index 5d47ea7de..a6f0f2155 100644 --- a/test_suite/tests/ui/remote/missing_field.stderr +++ b/test_suite/tests/ui/remote/missing_field.stderr @@ -1,5 +1,5 @@ error[E0063]: missing field `b` in initializer of `remote::S` - --> $DIR/missing_field.rs:11:18 + --> tests/ui/remote/missing_field.rs:11:18 | 11 | #[serde(remote = "remote::S")] | ^^^^^^^^^^^ missing `b` diff --git a/test_suite/tests/ui/remote/nonremote_getter.stderr b/test_suite/tests/ui/remote/nonremote_getter.stderr index 60d6d48ed..e510fdc83 100644 --- a/test_suite/tests/ui/remote/nonremote_getter.stderr +++ b/test_suite/tests/ui/remote/nonremote_getter.stderr @@ -1,5 +1,5 @@ error: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")] - --> $DIR/nonremote_getter.rs:4:1 + --> tests/ui/remote/nonremote_getter.rs:4:1 | 4 | / struct S { 5 | | #[serde(getter = "S::get")] diff --git a/test_suite/tests/ui/remote/unknown_field.rs b/test_suite/tests/ui/remote/unknown_field.rs index dd59cdcca..d21e7ffe0 100644 --- a/test_suite/tests/ui/remote/unknown_field.rs +++ b/test_suite/tests/ui/remote/unknown_field.rs @@ -1,4 +1,4 @@ -use serde_derive::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; mod remote { pub struct S { diff --git a/test_suite/tests/ui/remote/unknown_field.stderr b/test_suite/tests/ui/remote/unknown_field.stderr index 9e22ee9e7..5c851ce1e 100644 --- a/test_suite/tests/ui/remote/unknown_field.stderr +++ b/test_suite/tests/ui/remote/unknown_field.stderr @@ -1,11 +1,19 @@ error[E0609]: no field `b` on type `&remote::S` - --> $DIR/unknown_field.rs:12:5 + --> tests/ui/remote/unknown_field.rs:12:5 | 12 | b: u8, - | ^ help: a field with a similar name exists: `a` + | ^ unknown field + | +help: a field with a similar name exists + | +12 - b: u8, +12 + a: u8, + | error[E0560]: struct `remote::S` has no field named `b` - --> $DIR/unknown_field.rs:12:5 + --> tests/ui/remote/unknown_field.rs:12:5 | 12 | b: u8, - | ^ help: a field with a similar name exists: `a` + | ^ `remote::S` does not have this field + | + = note: all struct fields are already assigned diff --git a/test_suite/tests/ui/remote/wrong_de.stderr b/test_suite/tests/ui/remote/wrong_de.stderr index 937667481..be7b78783 100644 --- a/test_suite/tests/ui/remote/wrong_de.stderr +++ b/test_suite/tests/ui/remote/wrong_de.stderr @@ -1,10 +1,14 @@ error[E0308]: mismatched types - --> $DIR/wrong_de.rs:7:10 + --> tests/ui/remote/wrong_de.rs:7:10 | 7 | #[derive(Deserialize)] - | ^^^^^^^^^^^ - | | - | expected `u16`, found `u8` - | help: you can convert a `u8` to a `u16`: `Deserialize.into()` + | ^^^^^^^^^^^ expected `u16`, found `u8` +8 | #[serde(remote = "remote::S")] + | ----------- arguments to this struct are incorrect | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) +note: tuple struct defined here + --> tests/ui/remote/wrong_de.rs:4:16 + | +4 | pub struct S(pub u16); + | ^ + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/test_suite/tests/ui/remote/wrong_getter.stderr b/test_suite/tests/ui/remote/wrong_getter.stderr index b540bb5cc..c686ff55d 100644 --- a/test_suite/tests/ui/remote/wrong_getter.stderr +++ b/test_suite/tests/ui/remote/wrong_getter.stderr @@ -1,9 +1,17 @@ error[E0308]: mismatched types - --> $DIR/wrong_getter.rs:15:10 + --> tests/ui/remote/wrong_getter.rs:15:10 | 15 | #[derive(Serialize)] - | ^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^ + | | + | expected `&u8`, found `&u16` + | arguments to this function are incorrect | = note: expected reference `&u8` found reference `&u16` - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) +note: function defined here + --> $WORKSPACE/serde/src/private/ser.rs + | + | pub fn constrain(t: &T) -> &T { + | ^^^^^^^^^ + = note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/test_suite/tests/ui/remote/wrong_ser.stderr b/test_suite/tests/ui/remote/wrong_ser.stderr index 3d22e2d67..52f00470a 100644 --- a/test_suite/tests/ui/remote/wrong_ser.stderr +++ b/test_suite/tests/ui/remote/wrong_ser.stderr @@ -1,9 +1,17 @@ error[E0308]: mismatched types - --> $DIR/wrong_ser.rs:9:10 + --> tests/ui/remote/wrong_ser.rs:9:10 | 9 | #[derive(Serialize)] - | ^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^ + | | + | expected `&u8`, found `&u16` + | arguments to this function are incorrect | = note: expected reference `&u8` found reference `&u16` - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) +note: function defined here + --> $WORKSPACE/serde/src/private/ser.rs + | + | pub fn constrain(t: &T) -> &T { + | ^^^^^^^^^ + = note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr b/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr index 728d71ca2..03dcdaa9d 100644 --- a/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr +++ b/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr @@ -1,5 +1,5 @@ -error: unknown rename rule for #[serde(rename_all = "abc")] - --> $DIR/container_unknown_rename_rule.rs:4:22 +error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE" + --> tests/ui/rename/container_unknown_rename_rule.rs:4:22 | 4 | #[serde(rename_all = "abc")] | ^^^^^ diff --git a/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr b/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr index 7a52f37a8..02c970e4b 100644 --- a/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr +++ b/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr @@ -1,5 +1,5 @@ -error: unknown rename rule for #[serde(rename_all = "abc")] - --> $DIR/variant_unknown_rename_rule.rs:5:26 +error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE" + --> tests/ui/rename/variant_unknown_rename_rule.rs:5:26 | 5 | #[serde(rename_all = "abc")] | ^^^^^ diff --git a/test_suite/tests/ui/struct-representation/internally-tagged-tuple.stderr b/test_suite/tests/ui/struct-representation/internally-tagged-tuple.stderr index 7cf179895..9b25305d8 100644 --- a/test_suite/tests/ui/struct-representation/internally-tagged-tuple.stderr +++ b/test_suite/tests/ui/struct-representation/internally-tagged-tuple.stderr @@ -1,5 +1,5 @@ error: #[serde(tag = "...")] can only be used on enums and structs with named fields - --> $DIR/internally-tagged-tuple.rs:5:9 + --> tests/ui/struct-representation/internally-tagged-tuple.rs:4:9 | -5 | struct S(u8, u8); - | ^^^^^^^^ +4 | #[serde(tag = "type")] + | ^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/struct-representation/internally-tagged-unit.stderr b/test_suite/tests/ui/struct-representation/internally-tagged-unit.stderr index d75c4bd89..1961ee59e 100644 --- a/test_suite/tests/ui/struct-representation/internally-tagged-unit.stderr +++ b/test_suite/tests/ui/struct-representation/internally-tagged-unit.stderr @@ -1,7 +1,5 @@ error: #[serde(tag = "...")] can only be used on enums and structs with named fields - --> $DIR/internally-tagged-unit.rs:3:10 + --> tests/ui/struct-representation/internally-tagged-unit.rs:4:9 | -3 | #[derive(Serialize)] - | ^^^^^^^^^ - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) +4 | #[serde(tag = "type")] + | ^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/transparent/at_most_one.stderr b/test_suite/tests/ui/transparent/at_most_one.stderr index b6a234c01..4566668cd 100644 --- a/test_suite/tests/ui/transparent/at_most_one.stderr +++ b/test_suite/tests/ui/transparent/at_most_one.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] requires struct to have at most one transparent field - --> $DIR/at_most_one.rs:4:1 + --> tests/ui/transparent/at_most_one.rs:4:1 | 4 | / #[serde(transparent)] 5 | | struct S { diff --git a/test_suite/tests/ui/transparent/de_at_least_one.stderr b/test_suite/tests/ui/transparent/de_at_least_one.stderr index 42a02c0b7..97d7f52a8 100644 --- a/test_suite/tests/ui/transparent/de_at_least_one.stderr +++ b/test_suite/tests/ui/transparent/de_at_least_one.stderr @@ -1,11 +1,11 @@ error: #[serde(transparent)] requires at least one field that is neither skipped nor has a default - --> $DIR/de_at_least_one.rs:4:1 + --> tests/ui/transparent/de_at_least_one.rs:4:1 | -4 | / #[serde(transparent)] -5 | | struct S { -6 | | #[serde(skip)] -7 | | a: u8, -8 | | #[serde(default)] -9 | | b: u8, + 4 | / #[serde(transparent)] + 5 | | struct S { + 6 | | #[serde(skip)] + 7 | | a: u8, + 8 | | #[serde(default)] + 9 | | b: u8, 10 | | } | |_^ diff --git a/test_suite/tests/ui/transparent/enum.stderr b/test_suite/tests/ui/transparent/enum.stderr index 2181fa8ba..e14b4bb1f 100644 --- a/test_suite/tests/ui/transparent/enum.stderr +++ b/test_suite/tests/ui/transparent/enum.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] is not allowed on an enum - --> $DIR/enum.rs:4:1 + --> tests/ui/transparent/enum.rs:4:1 | 4 | / #[serde(transparent)] 5 | | enum E {} diff --git a/test_suite/tests/ui/transparent/ser_at_least_one.stderr b/test_suite/tests/ui/transparent/ser_at_least_one.stderr index 6e1c01b54..53775a910 100644 --- a/test_suite/tests/ui/transparent/ser_at_least_one.stderr +++ b/test_suite/tests/ui/transparent/ser_at_least_one.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] requires at least one field that is not skipped - --> $DIR/ser_at_least_one.rs:4:1 + --> tests/ui/transparent/ser_at_least_one.rs:4:1 | 4 | / #[serde(transparent)] 5 | | struct S { diff --git a/test_suite/tests/ui/transparent/unit_struct.stderr b/test_suite/tests/ui/transparent/unit_struct.stderr index d6371efac..7d7d2cb7d 100644 --- a/test_suite/tests/ui/transparent/unit_struct.stderr +++ b/test_suite/tests/ui/transparent/unit_struct.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] is not allowed on a unit struct - --> $DIR/unit_struct.rs:4:1 + --> tests/ui/transparent/unit_struct.rs:4:1 | 4 | / #[serde(transparent)] 5 | | struct S; diff --git a/test_suite/tests/ui/transparent/with_from.stderr b/test_suite/tests/ui/transparent/with_from.stderr index fd031d436..547eab2a8 100644 --- a/test_suite/tests/ui/transparent/with_from.stderr +++ b/test_suite/tests/ui/transparent/with_from.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] is not allowed with #[serde(from = "...")] - --> $DIR/with_from.rs:4:1 + --> tests/ui/transparent/with_from.rs:4:1 | 4 | / #[serde(transparent, from = "u64")] 5 | | struct S { diff --git a/test_suite/tests/ui/transparent/with_into.stderr b/test_suite/tests/ui/transparent/with_into.stderr index c8f72a376..5f40eaf9f 100644 --- a/test_suite/tests/ui/transparent/with_into.stderr +++ b/test_suite/tests/ui/transparent/with_into.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] is not allowed with #[serde(into = "...")] - --> $DIR/with_into.rs:4:1 + --> tests/ui/transparent/with_into.rs:4:1 | 4 | / #[serde(transparent, into = "u64")] 5 | | struct S { diff --git a/test_suite/tests/ui/transparent/with_try_from.stderr b/test_suite/tests/ui/transparent/with_try_from.stderr index f76f37480..be74b82b2 100644 --- a/test_suite/tests/ui/transparent/with_try_from.stderr +++ b/test_suite/tests/ui/transparent/with_try_from.stderr @@ -1,5 +1,5 @@ error: #[serde(transparent)] is not allowed with #[serde(try_from = "...")] - --> $DIR/with_try_from.rs:4:1 + --> tests/ui/transparent/with_try_from.rs:4:1 | 4 | / #[serde(transparent, try_from = "u64")] 5 | | struct S { diff --git a/test_suite/tests/ui/type-attribute/from.stderr b/test_suite/tests/ui/type-attribute/from.stderr index 1aae4c4db..1e869b38e 100644 --- a/test_suite/tests/ui/type-attribute/from.stderr +++ b/test_suite/tests/ui/type-attribute/from.stderr @@ -1,5 +1,5 @@ error: failed to parse type: from = "Option $DIR/from.rs:4:16 + --> tests/ui/type-attribute/from.rs:4:16 | 4 | #[serde(from = "Option $DIR/into.rs:4:16 + --> tests/ui/type-attribute/into.rs:4:16 | 4 | #[serde(into = "Option $DIR/try_from.rs:4:20 + --> tests/ui/type-attribute/try_from.rs:4:20 | 4 | #[serde(try_from = "Option $DIR/container.rs:4:9 +error: unexpected literal in nested attribute, expected ident + --> tests/ui/unexpected-literal/container.rs:4:9 | 4 | #[serde("literal")] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/unexpected-literal/field.stderr b/test_suite/tests/ui/unexpected-literal/field.stderr index 3895a660f..aa29a5e5b 100644 --- a/test_suite/tests/ui/unexpected-literal/field.stderr +++ b/test_suite/tests/ui/unexpected-literal/field.stderr @@ -1,5 +1,5 @@ -error: unexpected literal in serde field attribute - --> $DIR/field.rs:5:13 +error: unexpected literal in nested attribute, expected ident + --> tests/ui/unexpected-literal/field.rs:5:13 | 5 | #[serde("literal")] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/unexpected-literal/variant.stderr b/test_suite/tests/ui/unexpected-literal/variant.stderr index b7b2165c5..1e8035291 100644 --- a/test_suite/tests/ui/unexpected-literal/variant.stderr +++ b/test_suite/tests/ui/unexpected-literal/variant.stderr @@ -1,5 +1,5 @@ -error: unexpected literal in serde variant attribute - --> $DIR/variant.rs:5:13 +error: unexpected literal in nested attribute, expected ident + --> tests/ui/unexpected-literal/variant.rs:5:13 | 5 | #[serde("literal")] | ^^^^^^^^^ diff --git a/test_suite/tests/ui/unimplemented/required_by_dependency.rs b/test_suite/tests/ui/unimplemented/required_by_dependency.rs new file mode 100644 index 000000000..d3f88f113 --- /dev/null +++ b/test_suite/tests/ui/unimplemented/required_by_dependency.rs @@ -0,0 +1,6 @@ +struct MyStruct; + +fn main() { + serde_test::assert_ser_tokens(&MyStruct, &[]); + serde_test::assert_de_tokens(&MyStruct, &[]); +} diff --git a/test_suite/tests/ui/unimplemented/required_by_dependency.stderr b/test_suite/tests/ui/unimplemented/required_by_dependency.stderr new file mode 100644 index 000000000..2473a812e --- /dev/null +++ b/test_suite/tests/ui/unimplemented/required_by_dependency.stderr @@ -0,0 +1,113 @@ +error[E0277]: the trait bound `MyStruct: serde::Serialize` is not satisfied + --> tests/ui/unimplemented/required_by_dependency.rs:4:35 + | +4 | serde_test::assert_ser_tokens(&MyStruct, &[]); + | ----------------------------- ^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `serde_core::ser::Serialize` is not implemented for `MyStruct` + --> tests/ui/unimplemented/required_by_dependency.rs:1:1 + | +1 | struct MyStruct; + | ^^^^^^^^^^^^^^^ + = note: for local types consider adding `#[derive(serde::Serialize)]` to your `MyStruct` type + = note: for types from other crates check whether the crate offers a `serde` feature flag + = help: the following other types implement trait `serde_core::ser::Serialize`: + &'a T + &'a mut T + () + (T,) + (T0, T1) + (T0, T1, T2) + (T0, T1, T2, T3) + (T0, T1, T2, T3, T4) + and $N others +note: required by a bound in `assert_ser_tokens` + --> $CARGO/serde_test-$VERSION/src/assert.rs + | + | pub fn assert_ser_tokens(value: &T, tokens: &[Token]) + | ----------------- required by a bound in this function + | where + | T: ?Sized + Serialize, + | ^^^^^^^^^ required by this bound in `assert_ser_tokens` + +error[E0277]: the trait bound `MyStruct: serde::Deserialize<'de>` is not satisfied + --> tests/ui/unimplemented/required_by_dependency.rs:5:34 + | +5 | serde_test::assert_de_tokens(&MyStruct, &[]); + | ---------------------------- ^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `serde_core::de::Deserialize<'_>` is not implemented for `MyStruct` + --> tests/ui/unimplemented/required_by_dependency.rs:1:1 + | +1 | struct MyStruct; + | ^^^^^^^^^^^^^^^ + = note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyStruct` type + = note: for types from other crates check whether the crate offers a `serde` feature flag + = help: the following other types implement trait `serde_core::de::Deserialize<'de>`: + &'a Path + &'a [u8] + &'a str + () + (T,) + (T0, T1) + (T0, T1, T2) + (T0, T1, T2, T3) + and $N others +note: required by a bound in `assert_de_tokens` + --> $CARGO/serde_test-$VERSION/src/assert.rs + | + | pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) + | ---------------- required by a bound in this function + | where + | T: Deserialize<'de> + PartialEq + Debug, + | ^^^^^^^^^^^^^^^^ required by this bound in `assert_de_tokens` + +error[E0277]: can't compare `MyStruct` with `MyStruct` + --> tests/ui/unimplemented/required_by_dependency.rs:5:34 + | +5 | serde_test::assert_de_tokens(&MyStruct, &[]); + | ---------------------------- ^^^^^^^^^ no implementation for `MyStruct == MyStruct` + | | + | required by a bound introduced by this call + | + = help: the trait `PartialEq` is not implemented for `MyStruct` +note: required by a bound in `assert_de_tokens` + --> $CARGO/serde_test-$VERSION/src/assert.rs + | + | pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) + | ---------------- required by a bound in this function + | where + | T: Deserialize<'de> + PartialEq + Debug, + | ^^^^^^^^^ required by this bound in `assert_de_tokens` +help: consider annotating `MyStruct` with `#[derive(PartialEq)]` + | + 1 + #[derive(PartialEq)] + 2 | struct MyStruct; + | + +error[E0277]: `MyStruct` doesn't implement `Debug` + --> tests/ui/unimplemented/required_by_dependency.rs:5:34 + | +5 | serde_test::assert_de_tokens(&MyStruct, &[]); + | ---------------------------- ^^^^^^^^^ the trait `Debug` is not implemented for `MyStruct` + | | + | required by a bound introduced by this call + | + = note: add `#[derive(Debug)]` to `MyStruct` or manually `impl Debug for MyStruct` +note: required by a bound in `assert_de_tokens` + --> $CARGO/serde_test-$VERSION/src/assert.rs + | + | pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) + | ---------------- required by a bound in this function + | where + | T: Deserialize<'de> + PartialEq + Debug, + | ^^^^^ required by this bound in `assert_de_tokens` +help: consider annotating `MyStruct` with `#[derive(Debug)]` + | + 1 + #[derive(Debug)] + 2 | struct MyStruct; + | diff --git a/test_suite/tests/ui/unimplemented/required_locally.rs b/test_suite/tests/ui/unimplemented/required_locally.rs new file mode 100644 index 000000000..fab56751b --- /dev/null +++ b/test_suite/tests/ui/unimplemented/required_locally.rs @@ -0,0 +1,23 @@ +use serde::de::Deserialize; +use serde::ser::Serialize; + +fn to_string(_: &T) -> String +where + T: Serialize, +{ + unimplemented!() +} + +fn from_str<'de, T>(_: &'de str) -> T +where + T: Deserialize<'de>, +{ + unimplemented!() +} + +struct MyStruct; + +fn main() { + to_string(&MyStruct); + let _: MyStruct = from_str(""); +} diff --git a/test_suite/tests/ui/unimplemented/required_locally.stderr b/test_suite/tests/ui/unimplemented/required_locally.stderr new file mode 100644 index 000000000..e64fd4115 --- /dev/null +++ b/test_suite/tests/ui/unimplemented/required_locally.stderr @@ -0,0 +1,65 @@ +error[E0277]: the trait bound `MyStruct: serde::Serialize` is not satisfied + --> tests/ui/unimplemented/required_locally.rs:21:15 + | +21 | to_string(&MyStruct); + | --------- ^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Serialize` is not implemented for `MyStruct` + --> tests/ui/unimplemented/required_locally.rs:18:1 + | +18 | struct MyStruct; + | ^^^^^^^^^^^^^^^ + = note: for local types consider adding `#[derive(serde::Serialize)]` to your `MyStruct` type + = note: for types from other crates check whether the crate offers a `serde` feature flag + = help: the following other types implement trait `Serialize`: + &'a T + &'a mut T + () + (T,) + (T0, T1) + (T0, T1, T2) + (T0, T1, T2, T3) + (T0, T1, T2, T3, T4) + and $N others +note: required by a bound in `to_string` + --> tests/ui/unimplemented/required_locally.rs:6:8 + | + 4 | fn to_string(_: &T) -> String + | --------- required by a bound in this function + 5 | where + 6 | T: Serialize, + | ^^^^^^^^^ required by this bound in `to_string` + +error[E0277]: the trait bound `MyStruct: serde::Deserialize<'de>` is not satisfied + --> tests/ui/unimplemented/required_locally.rs:22:23 + | +22 | let _: MyStruct = from_str(""); + | ^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `Deserialize<'_>` is not implemented for `MyStruct` + --> tests/ui/unimplemented/required_locally.rs:18:1 + | +18 | struct MyStruct; + | ^^^^^^^^^^^^^^^ + = note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyStruct` type + = note: for types from other crates check whether the crate offers a `serde` feature flag + = help: the following other types implement trait `Deserialize<'de>`: + &'a Path + &'a [u8] + &'a str + () + (T,) + (T0, T1) + (T0, T1, T2) + (T0, T1, T2, T3) + and $N others +note: required by a bound in `from_str` + --> tests/ui/unimplemented/required_locally.rs:13:8 + | +11 | fn from_str<'de, T>(_: &'de str) -> T + | -------- required by a bound in this function +12 | where +13 | T: Deserialize<'de>, + | ^^^^^^^^^^^^^^^^ required by this bound in `from_str` diff --git a/test_suite/tests/ui/unknown-attribute/container.stderr b/test_suite/tests/ui/unknown-attribute/container.stderr index 402a1b603..bc781c079 100644 --- a/test_suite/tests/ui/unknown-attribute/container.stderr +++ b/test_suite/tests/ui/unknown-attribute/container.stderr @@ -1,5 +1,5 @@ error: unknown serde container attribute `abc` - --> $DIR/container.rs:4:9 + --> tests/ui/unknown-attribute/container.rs:4:9 | 4 | #[serde(abc = "xyz")] | ^^^ diff --git a/test_suite/tests/ui/unknown-attribute/field.stderr b/test_suite/tests/ui/unknown-attribute/field.stderr index b13754a36..dcacdf0a3 100644 --- a/test_suite/tests/ui/unknown-attribute/field.stderr +++ b/test_suite/tests/ui/unknown-attribute/field.stderr @@ -1,5 +1,5 @@ error: unknown serde field attribute `abc` - --> $DIR/field.rs:5:13 + --> tests/ui/unknown-attribute/field.rs:5:13 | 5 | #[serde(abc = "xyz")] | ^^^ diff --git a/test_suite/tests/ui/unknown-attribute/variant.stderr b/test_suite/tests/ui/unknown-attribute/variant.stderr index 64254f857..c53eb9514 100644 --- a/test_suite/tests/ui/unknown-attribute/variant.stderr +++ b/test_suite/tests/ui/unknown-attribute/variant.stderr @@ -1,5 +1,5 @@ error: unknown serde variant attribute `abc` - --> $DIR/variant.rs:5:13 + --> tests/ui/unknown-attribute/variant.rs:5:13 | 5 | #[serde(abc = "xyz")] | ^^^ diff --git a/test_suite/tests/ui/unsupported/union_de.stderr b/test_suite/tests/ui/unsupported/union_de.stderr index b7892d490..08292a151 100644 --- a/test_suite/tests/ui/unsupported/union_de.stderr +++ b/test_suite/tests/ui/unsupported/union_de.stderr @@ -1,5 +1,5 @@ error: Serde does not support derive for unions - --> $DIR/union_de.rs:4:1 + --> tests/ui/unsupported/union_de.rs:4:1 | 4 | / union Union { 5 | | x: u8, diff --git a/test_suite/tests/ui/unsupported/union_ser.stderr b/test_suite/tests/ui/unsupported/union_ser.stderr index 78d87c71e..46b9587b1 100644 --- a/test_suite/tests/ui/unsupported/union_ser.stderr +++ b/test_suite/tests/ui/unsupported/union_ser.stderr @@ -1,5 +1,5 @@ error: Serde does not support derive for unions - --> $DIR/union_ser.rs:4:1 + --> tests/ui/unsupported/union_ser.rs:4:1 | 4 | / union Union { 5 | | x: u8, diff --git a/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr b/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr index d3ff8c6e8..73217df6f 100644 --- a/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr @@ -1,5 +1,5 @@ error: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_newtype_field.rs:5:5 + --> tests/ui/with-variant/skip_de_newtype_field.rs:5:5 | 5 | / #[serde(deserialize_with = "deserialize_some_newtype_variant")] 6 | | Newtype(#[serde(skip_deserializing)] String), diff --git a/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr b/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr index ee7e37918..5632b67d8 100644 --- a/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr @@ -1,10 +1,10 @@ error: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_struct_field.rs:5:5 + --> tests/ui/with-variant/skip_de_struct_field.rs:5:5 | -5 | / #[serde(deserialize_with = "deserialize_some_other_variant")] -6 | | Struct { -7 | | #[serde(skip_deserializing)] -8 | | f1: String, -9 | | f2: u8, + 5 | / #[serde(deserialize_with = "deserialize_some_other_variant")] + 6 | | Struct { + 7 | | #[serde(skip_deserializing)] + 8 | | f1: String, + 9 | | f2: u8, 10 | | }, | |_____^ diff --git a/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr b/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr index f2cc90e80..e86efc429 100644 --- a/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr @@ -1,5 +1,5 @@ error: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_tuple_field.rs:5:5 + --> tests/ui/with-variant/skip_de_tuple_field.rs:5:5 | 5 | / #[serde(deserialize_with = "deserialize_some_other_variant")] 6 | | Tuple(#[serde(skip_deserializing)] String, u8), diff --git a/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr b/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr index 8f1be1632..b548bc1e4 100644 --- a/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr @@ -1,5 +1,5 @@ error: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)] - --> $DIR/skip_de_whole_variant.rs:5:5 + --> tests/ui/with-variant/skip_de_whole_variant.rs:5:5 | 5 | / #[serde(deserialize_with = "deserialize_some_unit_variant")] 6 | | #[serde(skip_deserializing)] diff --git a/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr index 5741bc4fc..8bbd738ee 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr @@ -1,5 +1,5 @@ error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_newtype_field.rs:5:5 + --> tests/ui/with-variant/skip_ser_newtype_field.rs:5:5 | 5 | / #[serde(serialize_with = "serialize_some_newtype_variant")] 6 | | Newtype(#[serde(skip_serializing)] String), diff --git a/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr index 8103680f6..b536e406f 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr @@ -1,5 +1,5 @@ error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_newtype_field_if.rs:5:5 + --> tests/ui/with-variant/skip_ser_newtype_field_if.rs:5:5 | 5 | / #[serde(serialize_with = "serialize_some_newtype_variant")] 6 | | Newtype(#[serde(skip_serializing_if = "always")] String), diff --git a/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr index 5b1e2301a..f67921598 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr @@ -1,10 +1,10 @@ error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_struct_field.rs:5:5 + --> tests/ui/with-variant/skip_ser_struct_field.rs:5:5 | -5 | / #[serde(serialize_with = "serialize_some_other_variant")] -6 | | Struct { -7 | | #[serde(skip_serializing)] -8 | | f1: String, -9 | | f2: u8, + 5 | / #[serde(serialize_with = "serialize_some_other_variant")] + 6 | | Struct { + 7 | | #[serde(skip_serializing)] + 8 | | f1: String, + 9 | | f2: u8, 10 | | }, | |_____^ diff --git a/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr index 4fc89d6a5..c06c34047 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr @@ -1,10 +1,10 @@ error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_struct_field_if.rs:5:5 + --> tests/ui/with-variant/skip_ser_struct_field_if.rs:5:5 | -5 | / #[serde(serialize_with = "serialize_some_newtype_variant")] -6 | | Struct { -7 | | #[serde(skip_serializing_if = "always")] -8 | | f1: String, -9 | | f2: u8, + 5 | / #[serde(serialize_with = "serialize_some_newtype_variant")] + 6 | | Struct { + 7 | | #[serde(skip_serializing_if = "always")] + 8 | | f1: String, + 9 | | f2: u8, 10 | | }, | |_____^ diff --git a/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr index 4ea2dda59..1e69da344 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr @@ -1,5 +1,5 @@ error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_tuple_field.rs:5:5 + --> tests/ui/with-variant/skip_ser_tuple_field.rs:5:5 | 5 | / #[serde(serialize_with = "serialize_some_other_variant")] 6 | | Tuple(#[serde(skip_serializing)] String, u8), diff --git a/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr index 1f8a81493..c6aadb2ef 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr @@ -1,5 +1,5 @@ error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_tuple_field_if.rs:5:5 + --> tests/ui/with-variant/skip_ser_tuple_field_if.rs:5:5 | 5 | / #[serde(serialize_with = "serialize_some_other_variant")] 6 | | Tuple(#[serde(skip_serializing_if = "always")] String, u8), diff --git a/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr b/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr index 20decdc43..ac376a5e8 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr @@ -1,5 +1,5 @@ error: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)] - --> $DIR/skip_ser_whole_variant.rs:5:5 + --> tests/ui/with-variant/skip_ser_whole_variant.rs:5:5 | 5 | / #[serde(serialize_with = "serialize_some_unit_variant")] 6 | | #[serde(skip_serializing)] diff --git a/test_suite/tests/ui/with/incorrect_type.rs b/test_suite/tests/ui/with/incorrect_type.rs new file mode 100644 index 000000000..c1502bb45 --- /dev/null +++ b/test_suite/tests/ui/with/incorrect_type.rs @@ -0,0 +1,23 @@ +use serde_derive::{Deserialize, Serialize}; + +mod w { + use serde::{Deserializer, Serializer}; + + pub fn deserialize<'de, D: Deserializer<'de>>(_: D) -> Result<(), D::Error> { + unimplemented!() + } + pub fn serialize(_: S) -> Result { + unimplemented!() + } +} + +#[derive(Serialize, Deserialize)] +struct W(#[serde(with = "w")] u8, u8); + +#[derive(Serialize, Deserialize)] +struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + +#[derive(Serialize, Deserialize)] +struct D(#[serde(deserialize_with = "w::deserialize")] u8, u8); + +fn main() {} diff --git a/test_suite/tests/ui/with/incorrect_type.stderr b/test_suite/tests/ui/with/incorrect_type.stderr new file mode 100644 index 000000000..0629bdb88 --- /dev/null +++ b/test_suite/tests/ui/with/incorrect_type.stderr @@ -0,0 +1,105 @@ +error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:14:10 + | +14 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` +15 | struct W(#[serde(with = "w")] u8, u8); + | --- required by a bound introduced by this call + | +help: the trait `Serializer` is implemented for `&mut Formatter<'a>` + --> $WORKSPACE/serde_core/src/ser/fmt.rs + | + | impl<'a> Serializer for &mut fmt::Formatter<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `w::serialize` + --> tests/ui/with/incorrect_type.rs:9:28 + | + 9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^^ required by this bound in `serialize` + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> tests/ui/with/incorrect_type.rs:15:25 + | +14 | #[derive(Serialize, Deserialize)] + | --------- unexpected argument #2 of type `__S` +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ + | +note: function defined here + --> tests/ui/with/incorrect_type.rs:9:12 + | + 9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^ + +error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:15:25 + | +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ the trait `Serializer` is not implemented for `&u8` + | +help: the trait `Serializer` is implemented for `&mut Formatter<'a>` + --> $WORKSPACE/serde_core/src/ser/fmt.rs + | + | impl<'a> Serializer for &mut fmt::Formatter<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: `?` operator has incompatible types + --> tests/ui/with/incorrect_type.rs:15:25 + | +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ expected `u8`, found `()` + | + = note: `?` operator cannot convert from `()` to `u8` + +error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:17:10 + | +17 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | -------------- required by a bound introduced by this call + | +help: the trait `Serializer` is implemented for `&mut Formatter<'a>` + --> $WORKSPACE/serde_core/src/ser/fmt.rs + | + | impl<'a> Serializer for &mut fmt::Formatter<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `w::serialize` + --> tests/ui/with/incorrect_type.rs:9:28 + | + 9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^^ required by this bound in `serialize` + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> tests/ui/with/incorrect_type.rs:18:35 + | +17 | #[derive(Serialize, Deserialize)] + | --------- unexpected argument #2 of type `__S` +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | ^^^^^^^^^^^^^^ + | +note: function defined here + --> tests/ui/with/incorrect_type.rs:9:12 + | + 9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^ + +error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:18:35 + | +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | ^^^^^^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` + | +help: the trait `Serializer` is implemented for `&mut Formatter<'a>` + --> $WORKSPACE/serde_core/src/ser/fmt.rs + | + | impl<'a> Serializer for &mut fmt::Formatter<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: `?` operator has incompatible types + --> tests/ui/with/incorrect_type.rs:21:37 + | +21 | struct D(#[serde(deserialize_with = "w::deserialize")] u8, u8); + | ^^^^^^^^^^^^^^^^ expected `u8`, found `()` + | + = note: `?` operator cannot convert from `()` to `u8` diff --git a/test_suite/tests/unstable/mod.rs b/test_suite/tests/unstable/mod.rs index b0c221e61..8060b2add 100644 --- a/test_suite/tests/unstable/mod.rs +++ b/test_suite/tests/unstable/mod.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Serialize}; +use serde_derive::{Deserialize, Serialize}; use serde_test::{assert_tokens, Token}; #[test]